【问题标题】:Python LRU cache's global and per instance behavioral differencesPython LRU 缓存的全局和每个实例的行为差异
【发布时间】:2022-05-23 14:36:28
【问题描述】:

我正在经历 Python 的 LRU 缓存装饰器的实现 details。为了正确理解 lru_cache 装饰器在不同场景中的行为,我还阅读了以下 SO 答案:

到目前为止,我可以看出这三种情况下的缓存行为是不同的:

  1. 在全局命名空间中装饰一个函数。
  2. 装饰类中的实例方法。
  3. 装饰类中的方法,该方法稍后会使用 staticmethodclassmethod 装饰器进行装饰。

第一种情况是幸福的路径,每个用lru_cache 装饰器装饰的函数都有自己的缓存。这已经很好了documented。在第二种情况下,缓存在类的多个实例之间共享,其中每个实例对于实例方法的相同参数将具有不同的键。这在我列出的最后一个问题中得到了很好的解释。在第三种情况下,缓存也在封装类的多个实例之间共享。但是,由于静态方法或类方法不将self 作为其第一个参数,因此类的实例不会为相同的参数创建单独的缓存条目。

我的问题是——什么实现细节定义了这种行为?在lru_cache函数的实现中,我只能看到_lru_cache_wrapper函数内部的一个本地缓存字典正在保存缓存条目。这是sn-p:

def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
    
    sentinel = object()          
    make_key = _make_key         
    PREV, NEXT, KEY, RESULT = 0, 1, 2, 3   

    cache = {} # This is a local dict, 
               # then how come the instance cache entries are shared?

我不明白的是,当 lru_cache 装饰器应用于驻留在类中的方法时,该本地缓存字典如何在类的实例之间共享?我希望它的行为与第一种情况相同,即每个实体都有自己的缓存并且没有共享任何内容。

【问题讨论】:

    标签: python python-3.x caching lru


    【解决方案1】:

    lru_cache 是从 functools 导入的,这让我想到,它根本不关心类或实例。

    class User(P):
    
        @lru_cache()
        def _func(self):
            return self.num**2
    
        @lru_cache()
        def _func2(self, a, b):
            return self.num*a*b
    

    _func 有一个参数是self_func2 有三个参数,self、a、b。 lru_cache关心函数有多少参数,而不关心参数是对象还是其他。

    :),具体实现的细节我没有去看,只是给点思路。

    【讨论】:

    • 当您使用 functools.lru_cache 装饰器装饰实例方法时,封装该方法的类的实例在持有它们的进程的生命周期内永远不会被垃圾收集。不鼓励这种模式。 rednafi.github.io/reflections/…
    猜你喜欢
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2015-07-19
    • 1970-01-01
    • 2017-01-14
    • 2011-05-25
    • 2013-08-02
    相关资源
    最近更新 更多