36

@functools.lru_cache在 Python 3.3 中使用。我想将缓存保存到一个文件中,以便在程序重新启动时恢复它。我该怎么办?

编辑 1可能的解决方案:我们需要腌制任何类型的可调用对象

酸洗问题__closure__

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

如果我尝试在没有它的情况下恢复该功能,我会得到:

TypeError: arg 5 (closure) must be tuple
4

5 回答 5

31

您无法使用 做您想做的事lru_cache,因为它不提供访问缓存的 API,并且在未来的版本中可能会用 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 的问题跟踪器中发现了一个将转储/加载添加到的功能请求lru_cache,但它没有被接受/实现。也许将来可以通过lru_cache.

于 2013-03-23T13:39:42.523 回答
9

你可以使用我的图书馆,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
于 2017-01-20T10:05:20.593 回答
3

考虑使用joblib.Memory持久缓存到磁盘。

由于磁盘很大,因此不需要 LRU 缓存方案。

于 2014-05-05T16:53:28.790 回答
1

除了公共 API 之外,您不应该接触装饰器实现中的任何内容,因此如果您想更改其行为,您可能需要复制其实现并自己添加必要的函数。请注意,缓存当前存储为循环双向链表,因此在保存和加载它时需要小心。

于 2013-03-23T10:12:47.337 回答
0

这是我写的可能对devcache有帮助的东西。

它旨在帮助您加快长时间运行方法的迭代。可以通过配置文件进行配置

@devcache(group='crm')
def my_method(a, b, c):  
    ...        

@devcache(group='db')
def another_method(a, b, c): 
    ...        

缓存可以刷新或与 yaml 配置文件一起使用,例如:

refresh: false # refresh true will ignore use_cache and refresh all cached data 
props:
    1:
        group: crm
        use_cache: false
    2:
        group: db
        use_cache: true

将刷新缓存my_method并使用缓存another_method

它不会帮助您腌制可调用对象,但它会完成缓存部分,并且可以直接修改代码以添加专门的序列化。

于 2021-05-15T13:48:49.667 回答