多くの Rails 開発者は、メモ化が何をどのように行うのかを完全には理解していないと思います。遅延ロードされたコレクション (Sequel データセットなど) を返すメソッドに適用されたり、引数を取らずにインスタンス変数に基づいて何かを計算するメソッドに適用されたりするのを見てきました。前者の場合、メモ化は単なるオーバーヘッドであり、後者の場合は厄介で追跡が困難なバグの原因となります。
次の場合はメモ化を適用しません
- 戻り値の計算には、わずかにコストがかかります。メモ化する価値があるためには、非常に高価で、さらに最適化できない必要があります。
- 戻り値は遅延ロードされているか、遅延ロードされる可能性があります
- メソッドは純粋な関数ではありません。つまり、同じ引数に対してまったく同じ値を返すことが保証されており、引数を使用してその作業を行うか、他の純粋な関数のみを使用します。インスタンス変数を使用するか、インスタンス変数を使用するメソッドを呼び出すと、メソッドは同じ引数に対して異なる結果を返す可能性があります。
上記の質問や回答のように、メモ化が適切でない状況は他にもありますが、これらはそれほど明白ではないと私が思う3つです。
最後の項目はおそらく最も重要です。メモ化は、メソッドへの引数に基づいて結果をキャッシュします。メソッドが次のように見える場合、メモ化することはできません。
def unmemoizable1(name)
"%s was here %s" % name, Time.now.strftime('%Y-%m-%d')
end
def unmemoizable2
find_by_shoe_size(@size)
end
ただし、どちらもメモ化を利用するように書き直すことができます (ただし、これら 2 つのケースでは、他の理由で行うべきではないことは明らかです)。
def unmemoizable1(name)
memoizable1(name, Time.now.strftime('%Y-%m-%d'))
end
def memoizable1(name, time)
"#{name} was here #{time}"
end
memoize :memoizable1
def unmemoizable2
memoizable2(@size)
end
def memoizable2(size)
find_by_shoe_size(size)
end
memoize :memoizable2
find_by_shoe_size
(副作用がない、または依存していないと仮定して)
秘訣は、メソッドから純粋な関数を抽出し、代わりにメモ化を適用することです。