functools.lru_cache是Python的标准库functools提供的一个功能强大的内置缓存装饰器,LRU代表Least Recently Used(最近最少使用),如果缓存容量满了,基于 LRU 策略,最近最少使用的条目会被移除。。它通过存储函数调用的结果来优化性能,尤其适用于那些输入输出关系固定且计算开销较大的函数。
参数解析
@lru_cache(maxsize=128, typed=False)
maxsize: 缓存的最大容量,也就是最多缓存多少个结果,默认值为128;超过容量时回按照最近最少使用策略淘汰旧的缓存;设置为None时表示无限制缓存,但时可能导致内存占用过多。typed: 区分参数类型,如果typed=True,则会把f(3)和f(3.0)当作不同的缓存条目;默认为False。
常见用法
递归函数优化
如斐波那契数列、阶乘等,递归计算往往涉及大量重复工作。使用 lru_cache 可以避免重复计算,提升性能。
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))
print(fibonacci.cache_info())
print(fibonacci(9))
print(fibonacci.cache_info())
运行结果:
55
CacheInfo(hits=8, misses=11, maxsize=128, currsize=11)
34
CacheInfo(hits=9, misses=11, maxsize=128, currsize=11)
第一次调用fibonacci(10),递归地计算了fibonacci(0)到fibonacci(10)的所有结果,每个结果再计算完成后存储到缓存中。由于递归中多次重复调用,有8次缓存命中,有11次未命中。
第二次调用fibonacci(9),由于结果再第一次调用fibonacci(10)的时候已经被缓存,所以fibonacci(9)的结果直接从该缓存中返回;缓存的存取速度非常快(类似字典查找),每次从缓存中取数据,完全避免了递归和计算的时间消耗。;缓存命中次数增加一次(hits=8便车给hits=9)。
数据库查询缓存
当访问慢速资源(如数据库、API)时,可以将查询结果缓存,避免多次访问相同的数据。
from functools import lru_cache
@lru_cache(maxsize=32)
def get_user_info(user_id):
# 假设这是一个耗时的数据库查询
print(f"Fetching data for user_id={user_id}")
return {"id": user_id, "name": f"User {user_id}"}
print(get_user_info(1)) # 第一次调用会执行查询
print(get_user_info(1)) # 第二次调用直接返回缓存结果
复杂计算结果缓存
对于复杂的数学运算或数据处理,缓存可以显著减少运算时间。
其他用法
清理缓存
如果需要清空缓存,可以使用cache_clear()方法:
fibonacci.cache_clear()
获取缓存统计信息
cache_info提供了缓存的命中次数、未命中次数、当前缓存大小等统计信息。
info = fibonacci.cache_info()
print(info) # 输出类似:CacheInfo(hits=9, misses=11, maxsize=128, currsize=11)
注意事项
- 缓存易导致内存占用过大:对于大数据或者无界递归,使用
maxsize=None会导致内存爆满。应根据实际需要设置合适的maxsize。 - 不适用于带有可变参数的函数:如果函数的参数是列表、字典等可变类型,
lru_cache 无法正常工作(因为参数必须可哈希)。解决办法是将参数转换为不可变类型(如元组)。 - 仅缓存函数结果:
lru_cache只缓存函数结果,不会缓存其他副作用(如打印日志、写文件等)。
总结
functools.lru_cache 是一个轻量级、高效的缓存工具,非常适合对纯函数的结果进行缓存以提高性能。通过 maxsize 控制缓存容量,结合 cache_info() 和 cache_clear() 提供的工具,可以在大多数场景下灵活使用。
如果需求更复杂,可以考虑引入第三方缓存工具。