在Python >= 3.2中将functools.lru_cache缓存存储到文件

46 投票
7 回答
18620 浏览
提问于 2025-04-17 20:03

我在使用Python 3.3中的@functools.lru_cache,想把缓存保存到一个文件里,这样下次程序重启的时候就能恢复这些缓存。请问我该怎么做呢?

编辑 1 可能的解决方案:我们需要对任何可调用对象进行序列化

序列化__closure__时遇到的问题:

_pickle.PicklingError: Can't pickle <class 'cell'>: attribute lookup builtins.cell failed

如果我尝试在没有它的情况下恢复这个函数,我会得到:

TypeError: arg 5 (closure) must be tuple

7 个回答

7

可以考虑使用 joblib.Memory 来实现持久化缓存,也就是把数据存储到硬盘上。

因为硬盘的容量非常大,所以其实不需要使用LRU缓存这种方式。

13

你可以使用我写的一个库,叫做 mezmorize

import random
from mezmorize import Cache

cache = Cache(CACHE_TYPE='filesystem', CACHE_DIR='cache')


@cache.memoize()
def add(a, b):
    return a + b + random.randrange(0, 1000)

>>> add(2, 5)
727
>>> add(2, 5)
727
44

你不能用 lru_cache 来实现你想要的功能,因为它没有提供访问缓存的接口,而且将来可能会用C语言重写。如果你真的想保存缓存,就得用其他方法,这些方法能让你访问缓存。

自己写一个缓存其实很简单。比如:

from functools import wraps

def cached(func):
    func.cache = {}
    @wraps(func)
    def wrapper(*args):
        try:
            return func.cache[args]
        except KeyError:
            func.cache[args] = result = func(*args)
            return result   
    return wrapper

然后你可以把它当作装饰器来使用:

>>> @cached
... def fibonacci(n):
...     if n < 2:
...             return n
...     return fibonacci(n-1) + fibonacci(n-2)
... 
>>> fibonacci(100)
354224848179261915075L

并且可以获取 cache

>>> fibonacci.cache
{(32,): 2178309, (23,): 28657, ... }

接着你可以随意地对缓存进行序列化和反序列化,加载缓存可以用:

fibonacci.cache = pickle.load(cache_file_object)

我在python的bug跟踪系统里找到一个关于在 lru_cache 中添加序列化和反序列化功能的 功能请求,但这个请求没有被接受或实现。也许将来会有内置的支持来实现这些操作。

撰写回答