Python functools lru_cache 与实例方法 : release object

标签 python caching python-decorators lru functools

如何在类中使用 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 的推荐方式是什么?

我知道两种解决方法: Use per instance cachesmake the cache ignore object (不过,这可能会导致错误的结果)

最佳答案

这不是最干净的解决方案,但对程序员来说是完全透明的:

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

关于Python functools lru_cache 与实例方法 : release object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33672412/

相关文章:

database - 分布式设置上的 JanusGraph 数据库缓存

python - 使用 Python 装饰器为方法添加方法

python - 用于跟踪/记录耗时的优雅 Python 解决方案?

Python 装饰器强制显式传递参数

python - Python 2 和 Python 3 中的整数除法

html - 在 <audio> 标签中强制缓存 MP3/OGG

python - 如何让 Django 的错误邮件报告 `locals()` ?

java - hibernate如何维护多个java实例的缓存

python - 不寻常的符号 - python

python - Pandas 时间序列分析 - 总结数据帧中的状态变化/删除冗余日期