Python lru_cache:currsize < misses < maxsize 如何?

Car*_*ten 6 python caching lru

我有一个类,其中的方法用注释进行了lru_cache注释

CACHE_SIZE=16384

class MyClass:
    [...]

    @lru_cache(maxsize=CACHE_SIZE)
    def _my_method(self, texts: Tuple[str]):
       <some heavy text processing>

    def cache_info(self):
        return self._my_method.cache_info()

Run Code Online (Sandbox Code Playgroud)

运行一段时间后,我通过方法查看缓存统计信息cache_info()

c = MyClass()
[...]
c.cache_info()

{
  "hits":9348,
  "misses":4312,
  "maxsize":16384,
  "currsize":2588
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何currsize小于missesAND 小于maxsize

我的理解:对于每次未命中,结果都会添加到缓存中,从而增加当前大小。仅当当前大小达到最大大小时,才会删除缓存结果。由于此处尚未达到最大大小,因此应缓存每个未命中,因此此时currsize应相等。misses然而,这似乎并不是它的工作方式。

sj9*_*126 4

如果您的程序是多线程或递归的(基本上,任何类型的条件都_my_method()可能在另一个调用部分完成时再次调用),那么就可以看到您正在经历的行为。

lru_cache()是线程感知的,并使用以下一组步骤进行大小限制的缓存:

  • 从包装函数的参数中创建一个哈希键
  • 将缓存锁定在一个with块中:
    • 在缓存中查找 key
    • 如果key在缓存中,则返回缓存的值
    • 否则,如果缓存中没有该键,则加misses1
  • 调用包装函数
  • 再次锁定缓存
    • 如果结果现在在缓存中,则返回它
    • 如果结果仍然不在缓存中,请添加它,可能会删除较旧的条目等。

换句话说,在调用包装函数时,缓存的值可能已被另一个线程添加,但它仍然被视为未命中。如果您多次调用_my_method()查找相同的缺失键,导致misses增加,但随后导致该键在_my_method()完成时出现在缓存中,misses将高于currsize