メモリをリークすることなく、クラス内でfunctoolsのlru_cacheをどのように使用できますか?次の最小限の例では、foo
インスタンスは、スコープ外になり、リファラー(lru_cache以外)がなくても解放されません。
from functools import lru_cache
class BigClass:
pass
class Foo:
def __init__(self):
self.big = BigClass()
@lru_cache(maxsize=16)
def cached_method(self, x):
return x + 5
def fun():
foo = Foo()
print(foo.cached_method(10))
print(foo.cached_method(10)) # use cache
return 'something'
fun()
しかし、foo
、したがってfoo.big
(a BigClass
)はまだ生きています
import gc; gc.collect() # collect garbage
len([obj for obj in gc.get_objects() if isinstance(obj, Foo)]) # is 1
つまり、Foo/BigClassインスタンスはまだメモリに常駐しています。 Foo
(del Foo
)を削除しても解放されません。
Lru_cacheがインスタンスを保持しているのはなぜですか?キャッシュは実際のオブジェクトではなくハッシュを使用していませんか?
クラス内でlru_cachesを使用する推奨方法は何ですか?
私は2つの回避策を知っています: インスタンスキャッシュごとに使用 または キャッシュにオブジェクトを無視させる (ただし、誤った結果になる可能性があります)
これは最もクリーンなソリューションではありませんが、プログラマーには完全に透過的です。
import functools
import weakref
def memoized_method(*lru_args, **lru_kwargs):
def decorator(func):
@functools.wraps(func)
def wrapped_func(self, *args, **kwargs):
# We're storing the wrapped method inside the instance. If we had
# a strong reference to self the instance would never die.
self_weak = weakref.ref(self)
@functools.wraps(func)
@functools.lru_cache(*lru_args, **lru_kwargs)
def cached_method(*args, **kwargs):
return func(self_weak(), *args, **kwargs)
setattr(self, func.__name__, cached_method)
return cached_method(*args, **kwargs)
return wrapped_func
return decorator
lru_cache
とまったく同じパラメーターを受け取り、まったく同じように機能します。ただし、self
をlru_cache
に渡すことはなく、インスタンスごとにlru_cache
を使用します。
この使用例では、methodtools
を紹介します。
pip install methodtools
インストールする https://pypi.org/project/methodtools/
その後、コードはfunctoolsをmethodtoolsに置き換えるだけで機能します。
from methodtools import lru_cache
class Foo:
@lru_cache(maxsize=16)
def cached_method(self, x):
return x + 5
もちろん、GCテストも0を返します。
python 3.8はfunctools
モジュールに cached_property
デコレーターを導入しました。テストすると、インスタンスが保持されないようです。
python 3.8に更新したくない場合は、 ソースコード を使用できます。必要なのは、RLock
をインポートして_NOT_FOUND
を作成することだけです。オブジェクト。意味:
from threading import RLock
_NOT_FOUND = object()
class cached_property:
# https://github.com/python/cpython/blob/master/Lib/functools.py#L913
...