本質的に、ブロックが終了するまで、スタック上のその部分の下のすべての呼び出しによって到達可能な変数をスタックに配置したいと考えています。Java では、メソッドからアクセスできるサポート メソッドを備えた静的スレッド ローカルを使用してこれを解決します。
典型的な例: リクエストを受け取り、データベース接続を開きます。リクエストが完了するまで、すべてのコードでこのデータベース接続を使用する必要があります。要求を終了して閉じた後、データベース接続を閉じます。
これが必要なのは、レポートジェネレーターです。各レポートは複数の部分で構成され、各部分は異なる計算に依存する場合があり、異なる部分が同じ計算に部分的に依存する場合もあります。重い計算を繰り返したくないので、それらをキャッシュする必要があります。私の考えは、メソッドをキャッシュ デコレータで装飾することです。キャッシュは、メソッド名とモジュールに基づいて id を作成し、その引数は、これがスタック変数で既に計算されているかどうかを調べ、そうでない場合はメソッドを実行します。
現在の実装を示すことで明確にしようと思います。私がやりたいのは、計算を実装するためのコードを単純化することです。
まず、MathContext と呼ぶ中央キャッシュ アクセス オブジェクトがあります。
class MathContext(object):
def __init__(self, fn):
self.fn = fn
self.cache = dict()
def get(self, calc_config):
id = create_id(calc_config)
if id not in self.cache:
self.cache[id] = calc_config.exec(self)
return self.cache[id]
fn 引数は、コンテキストが関連して作成されるファイル名であり、そこからデータを読み取って計算することができます。
次に、Calculation クラスがあります。
class CalcBase(object):
def exec(self, math_context):
raise NotImplementedError
そして、これはばかげたフィボナッチの例です。メソッドは実際には再帰的ではなく、代わりに大量のデータセットで機能しますが、他の計算にどのように依存するかを示すために機能します。
class Fibonacci(CalcBase):
def __init__(self, n): self.n = n
def exec(self, math_context):
if self.n < 2: return 1
a = math_context.get(Fibonacci(self.n-1))
b = math_context.get(Fibonacci(self.n-2))
return a+b
代わりにフィボナッチにしたいのは、装飾されたメソッドです。
@cache
def fib(n):
if n<2: return 1
return fib(n-1)+fib(n-2)
math_context の例では、math_context が範囲外になると、キャッシュされた値もすべて範囲外になります。デコレータにも同じことが必要です。すなわち。ポイント X では、@cache によってキャッシュされたものはすべて参照解除されて gced されます。