@lru_cache默认maxsize=none导致内存持续增长,须显式设限;实例方法缓存含self易致冗余;参数须可哈希;不支持异步函数;缓存泄漏需检查引用链。

lru_cache 不清空会持续占内存
Python 的 @lru_cache 默认缓存无限增长,一旦函数被高频调用且参数组合多,缓存对象不会自动释放,最终拖垮进程内存。这不是“缓存没命中”的问题,而是缓存本身成了内存黑洞。
常见错误现象:MemoryError 突然出现、ps aux 显示 Python 进程 RSS 持续上涨、用 tracemalloc 定位到大量 functools._lru_cache_wrapper 实例。
- 必须显式设
maxsize,比如@lru_cache(maxsize=128),不写等于maxsize=None(即无上限) - 若逻辑上允许缓存复用但又怕累积,优先用小固定值(如 32 或 64),而非依赖“默认够用”
- 调试时可用
your_func.cache_info()查看当前命中/未命中/最大容量,别等 OOM 才想起查
类方法加 lru_cache 忘了 self 导致缓存错乱
@lru_cache 作用在实例方法上时,self 是缓存键的一部分 —— 但多数人没意识到:不同实例调用同一方法,哪怕参数完全一样,也会各自缓存一份。这既浪费内存,又可能掩盖状态不一致问题。
使用场景:工具类中封装了开销大的计算逻辑,想复用结果,但误把方法当纯函数用了。
立即学习“Python免费学习笔记(深入)”;
- 如果方法不依赖实例状态(即没读
self.xxx),改用静态方法 +@staticmethod+@lru_cache - 如果必须是实例方法且需跨实例共享缓存,手动把缓存移到类变量或模块级字典里,别依赖装饰器自动行为
- 切记:缓存键是
(self, *args, **kwargs)全量元组,self的id()不同就绝不复用
缓存对象含不可哈希内容直接报错
只要参数里有 dict、list、set 或自定义类(没实现 __hash__),@lru_cache 一调用就抛 TypeError: unhashable type。这不是配置问题,是底层用字典存缓存,键必须可哈希。
性能影响:有人试图把 json.dumps(args) 当键绕过,但序列化本身开销大,反而抵消缓存收益。
- 检查所有入参类型,尤其注意隐式传入的
**kwargs—— 即便你没显写,调用方可能塞了 dict - 若必须缓存含非哈希结构的数据,提前转换为可哈希形式,例如用
tuple(sorted(kwargs.items()))代替原kwargs - 更稳妥的做法:在函数入口做参数归一化,把 list 转 tuple、dict 转 frozenset(tuple(sorted(d.items()))),再进缓存逻辑
异步函数不能直接套 lru_cache
@lru_cache 只支持同步函数,对 async def 直接装饰会静默失效 —— 表面不报错,实际每次调用都走新路径,缓存形同虚设。这是最隐蔽的“以为缓存了,其实没缓存”陷阱。
错误现象:压测时 QPS 上不去、CPU 持续高、日志显示重复执行耗时逻辑,但 cache_info() 始终是 CacheInfo(hits=0, ...)。
- 别给
async def加@lru_cache,它根本不会生效 - 需要异步缓存,用
aiocache或async_lru这类专为协程设计的库 - 若只是想“先同步缓存再 await”,把耗时计算部分拆成独立同步函数并缓存,再在 async 函数里调它










