@lru_cache decorator缓存未命中过多



如何配置lru_cache以根据实际接收到的值对其缓存进行键控,而不是如何调用函数?

>>> from functools import lru_cache
>>> @lru_cache
... def f(x=2):
...     print("reticulating splines...")
...     return x ** 2
...
>>> f()
reticulating splines...
4
>>> f(2)
reticulating splines...
4
>>> f(x=2)
reticulating splines...
4

换句话说,只有上面的第一个调用应该是缓存未命中,另外两个应该是缓存命中。

要做到这一点,您必须完成将参数绑定到形式参数的过程。实际的过程是在没有公共接口的C代码中实现的,但在inspect中有一个(慢得多(的重新实现。这大约比正常使用functools.lru_cache慢100倍:

import functools
import inspect
def mycache(f=None, /, **kwargs):
def inner(f):
sig = inspect.signature(f)
f = functools.lru_cache(**kwargs)(f)
@functools.wraps(f)
def wrapper(*args, **kwargs):
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
return f(*bound.args, **bound.kwargs)
return wrapper
if f:
return inner(f)
return inner
@mycache
def f(x):
print("reticulating splines...")
return x ** 2

如果这种方法的性能损失太大,您可以使用以下技巧,它需要更多的代码复制,但运行速度要快得多,仅比正常使用lru_cache慢约2倍(有时使用关键字参数会更快(:

@functools.lru_cache
def _f(x):
print("reticulating splines...")
return x ** 2
def f(x=2):
return _f(x)

这使用更快的C级参数绑定来规范化对记忆助手函数的调用,但需要复制函数的参数3次:一次在外部函数的签名中,一次在助手的签名中和一次在对助手的调用中。

相关内容

  • 没有找到相关文章

最新更新