lru_cache默认仅内存缓存且不持久化,进程退出即丢失;需手动结合pickle与文件I/O实现本地磁盘缓存,或直接使用diskcache库替代以支持跨重启、并发安全及自动序列化。

lru_cache 默认只内存缓存,不落盘
functools.lru_cache 本质是装饰器,它把函数调用结果存在内存里,进程一退出就全丢。想“本地缓存”,得自己加一层文件序列化逻辑——lru_cache 本身不支持写磁盘。
常见误操作:直接给耗时函数加 @lru_cache 就以为下次启动还能用,结果发现缓存全空。这是因为缓存对象随 Python 解释器生命周期结束而销毁。
手动组合 pickle + lru_cache 实现重启可用的本地缓存
核心思路:用 lru_cache 管理内存热数据,同时在函数入口/出口同步读写磁盘文件(比如 pickle 或 json)。关键不是替换 lru_cache,而是补上它缺的持久化环节。
- 缓存文件路径建议用函数名 + 参数哈希生成,避免冲突:
f"{func.__name__}_{hash(str(args) + str(kwargs))}.pkl" - 先查磁盘文件是否存在且未过期(可加时间戳字段),存在则直接加载并塞进
lru_cache;否则执行原函数,再保存到磁盘 + 写入内存缓存 - 注意
pickle不安全,别加载不可信来源的缓存文件;若参数含不可序列化对象(如lambda、打开的文件句柄),会直接报PicklingError - 并发写同一缓存文件时可能出错,简单场景加
threading.Lock,生产环境建议用sqlite或diskcache库
比手写更稳的选择:用 diskcache 替代 lru_cache
如果目标就是“本地缓存且跨进程/重启有效”,diskcache 库是更直接的解法——它把 lru_cache 的接口逻辑复刻到了磁盘后端,API 几乎一致,但默认就持久化。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
示例:
import diskcache as dc
cache = dc.Cache('./mycache')
<p>@cache.memoize()
def expensive_func(x, y):
return x ** y + 100</p>它自动处理:
- 序列化(用
cloudpickle,比pickle更强) - 文件锁和并发读写
- LRU 驱逐策略(可设
size_limit) - 过期时间(
expire参数)
唯一要注意的是:首次安装需 pip install diskcache,且缓存目录要确保有读写权限。
参数变化时 lru_cache 命中失败的典型表现
加了 @lru_cache 却总不命中?大概率是参数类型或值“看似一样实则不同”。比如:
- 传
list和tuple被视为不同参数(lru_cache按==判断,但[1,2] != (1,2)) - 浮点数精度误差导致
3.1415926和3.1415926000000001不匹配 - 使用了可变默认参数(如
def f(x, cache=[])),每次调用共享同一对象,lru_cache会把它当新参数 - 类实例方法没加
self到缓存键里(应改用@lru_cache在staticmethod或提取纯函数)
调试技巧:临时加 @lru_cache(maxsize=None, typed=True),开启 typed 可区分 int(1) 和 float(1.0);再用 expensive_func.cache_info() 查命中率。
缓存路径权限、参数可哈希性、序列化兼容性——这三个点,比“怎么加装饰器”更容易决定本地缓存能不能真正跑起来。

















