@
functools.
lru_cache
(maxsize=128, typed=False)
@lru_cache装饰器可以提供缓存的功能,缓存 maxsize 组传入参数,在下次以相同参数调用时直接返回上一次的结果。用以节约高开销或I/O函数的调用时间。
举个列子:
普通计算斐波那契数列的递归代码
import timeit
cnt = 0
def fib(n):
if n == 1:
global cnt
cnt += 1
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(timeit.timeit('fib(36)', number=1, globals=globals()))
print("fib(1) 调用次数:%d" % cnt)
输出
8.1090482
fib(1) 调用次数:14930352
使用lru_cache装饰器后,每次递归若有相同的参数调用,直接从缓存中取值,则fib(1)的调用只有一次,效率明显提升
import timeit
from functools import lru_cache
cnt = 0
@lru_cache(maxsize=None, typed=False)
def fib(n):
if n == 1:
global cnt
cnt += 1
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(timeit.timeit('fib(36)', number=1, globals=globals()))
print("fib(1) 调用次数:%d" % cnt)
print(fib.cache_info()) # 查看缓存信息
输出
1.5499999999999997e-05
fib(1) 调用次数:1
CacheInfo(hits=34, misses=37, maxsize=None, currsize=37)
# 命中次数 hits,未命中次数 misses ,最大缓存数量 maxsize 和 当前缓存大小 currsize
总结:
如果 maxsize 设为 None
,LRU 特性将被禁用且缓存可无限增长。
如果 typed 设置为true,不同类型的函数参数将被分别缓存。例如, f(3)
和 f(3.0)
将被视为不同而分别缓存。
被包装的函数配有一个 cache_parameters()
函数,该函数返回一个新的 dict
用来显示 maxsize 和 typed 的值。 这只是出于显示信息的目的。 改变值没有任何效果。
为了衡量缓存的有效性以便调整 maxsize 形参,被装饰的函数带有一个 cache_info()
函数。当调用 cache_info()
函数时,返回一个具名元组,包含命中次数 hits,未命中次数 misses ,最大缓存数量 maxsize 和 当前缓存大小 currsize。在多线程环境中,命中数与未命中数是不完全准确的。
该装饰器也提供了一个用于清理/使缓存失效的函数 cache_clear()
。
原始的未经装饰的函数可以通过 __wrapped__
属性访问。它可以用于检查、绕过缓存,或使用不同的缓存再次装饰原始函数。
LRU(最久未使用算法)缓存 在最近的调用是即将到来的调用的最佳预测值时性能最好(例如,新闻服务器上最热门文章倾向于每天更改)。 缓存的大小限制可确保缓存不会在长期运行进程如网站服务器上无限制地增长。
一般来说,LRU缓存只在当你想要重用之前计算的结果时使用。因此,用它缓存具有副作用的函数、需要在每次调用时创建不同、易变的对象的函数或者诸如time()或random()之类的不纯函数是没有意义的。