Python functools.lru_cache自动缓存应用小结
作者:atwdy
基本介绍
lru_cache是Python3.2版本在functools标准模块中引入的装饰器,用于实现最近最少使用(Least Recently Used, LRU)缓存策略,适用于所有相同输入对应相同输出的确定性函数,即缓存函数的参数和返回值的映射,只要下次调用参数相同,就直接返回缓存的结果,不再执行函数体。
工作原理:
- 缓存命中:当使用相同的参数调用被装饰的函数时,函数不会真正执行,而是直接从缓存中返回结果。
- 缓存未命中:当参数不在缓存中时,函数正常执行,并将结果存入缓存。
- 缓存淘汰:当缓存(不同参数个数)达到设定的最大容量(由 maxsize参数指定)时,它会自动淘汰最久未被使用的结果,以控制内存占用。
可通过参数maxsize=n指定缓存的最大容量,参数值为None表示无限制缓存,会缓存所有不同参数组合的函数返回值,性能最优但存在内存溢出的风险,根据实际情况设置。
在递归中的应用
lru_cache虽然适用于所有确定性的函数,但在递归场景中使用特别合适,因为递归场景中往往需要重复计算相同的子问题。以下面斐波那契数列为例:
def fib(num):
if num == 0 or num == 1:
return num
return fib(num - 1) + fib(num - 2)
fib(5)对应的递归树:
fib(5)
/ \
fib(4) fib(3)
/ \ / \
fib(3) fib(2) fib(2) fib(1)
/ \ / \ / \
fib(2) f(1) f(1)f(0) f(1)f(0)
/ \
f(1) f(0)如果不使用缓存,fib(3)和fib(2)都被重复计算了多次,如果把这棵递归树看成满二叉树,fib(n)一共有n层,每层的节点数量分别为 2 0 2^0 20, 2 1 2^1 21, 2 2 2^2 22, …, 2 n 2^n 2n, 那么总的时间复杂度 O ( 2 n ) O(2^n) O(2n)。
如果使用了lru,函数会在第一次计算矩形标记的fib(0),fib(1),…, fib(5)时将每个参数对应的函数值缓存,也就是对于fib(5)的整个计算流程中,标记的6个记录在第一次计算时未命中缓存,会执行函数并将这6个记录的结果缓存,在后续计算中直接读取圆形标记的fib(1),fib(2),fib(3)的缓存,直接读取3次缓存就可以直接结束整个函数。

对于上面的分析可使用被装饰函数的cache_info方法输出详细的缓存信息查看:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(num):
if num == 0 or num == 1:
return num
return fib(num - 1) + fib(num - 2)
print(fib(5))
print(fib.cache_info())
被
lru_cache装饰的函数也会自动同时绑定上cache_info方法,用于显示整个函数计算过程中的缓存命中情况,返回4个字段,含义分别是:
1)hits:缓存命中次数
2)misses:缓存未命中次数
3)maxsize:缓存最大容量
4)currsize:当前已缓存数量
缓存清空
lru_cache会为所有同名的函数全局维护一个独立的缓存结构,不同函数之间的缓存空间不冲突。除非手动cache_clear,否则缓存不会自动清除。
到此这篇关于Python functools.lru_cache自动缓存应用小结的文章就介绍到这了,更多相关Python functools.lru_cache缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
