我有一个带有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()
运行一段时间后,我通过cache_info()
方法查看缓存统计信息:
c = MyClass()
[...]
c.cache_info()
{
"hits":9348,
"misses":4312,
"maxsize":16384,
"currsize":2588
}
我的问题是:currsize
如何小于misses
且小于maxsize
?
我对的理解是:对于每一次失败,结果都被添加到缓存中,因此增加了当前的大小。只有当当前大小达到最大大小时,缓存的结果才会被删除。因为这里还没有达到最大大小,所以应该缓存每个缺失,所以此时currsize
应该等于misses
。然而,这似乎不是工作的方式。
如果你的程序是多线程的,或者是递归的——基本上,任何一种_my_method()
可能在另一个调用部分完成的情况下被再次调用——那么就有可能看到你正在经历的行为。
lru_cache()
是线程感知的,并使用以下一组步骤进行大小限制的缓存:
- 从包装函数的参数中生成一个哈希键
- 锁定
with
块中的缓存:- 在缓存中查找键
- 如果键在缓存中,返回缓存值
- else,如果键不在缓存中,则增加
misses
1
- 调用包装函数 再次锁定缓存
- 如果结果现在在缓存中,返回它
- 如果结果仍然不在缓存中,添加它,可能删除旧的条目,等等。
换句话说,当调用包装函数时,缓存的值可能已经被另一个线程添加,但它仍然被算作遗漏。如果您多次调用_my_method()
查找相同的缺失键,导致misses
增加,但随后导致在_my_method()
完成时键出现在缓存中,misses
将高于currsize
。