用于后续在 python 中运行的缓存工具

Sav*_*esh 5 python caching

我是初学者。对不起,如果我的问题很幼稚。python 中的缓存工具是否适用于后续运行?

import cachetools
import time


@cachetools.cached({})
def find_sum(n):
    time.sleep(5)
    return n+2


print find_sum(2)
print find_sum(3)
print find_sum(2)
Run Code Online (Sandbox Code Playgroud)

因此,在第一次运行期间,第三次调用更快,但下次我运行文件时,我希望第一次调用更快并从缓存中获取结果。缓存工具可以做到这一点吗?

aba*_*ert 10

cachetools不能立即执行此操作。但是添加起来非常容易。

您可以将任何您想要的可变映射传递给记忆装饰器。你正在使用一个普通的旧字典,而字典是微不足道的。即使您使用库提供的一种奇特的缓存实现,它们也很容易被pickle。1

所以:

import cachetools
import pickle
import time

try:
    with open('mycache.pickle', 'rb') as f:
        cache = pickle.load(f)
except FileNotFoundError:
    cache = {} # or cachetools.LRUCache(maxsize=5) or whatever you want

@cachetools.cached(cache)
def find_sum(n):
    time.sleep(5)
    return n+2

print(find_sum(2))
print(find_sum(3))
print(find_sum(2))

with open('mycache.pickle', 'wb') as f:
    pickle.dump(cache, f)
Run Code Online (Sandbox Code Playgroud)

当然你可以添加:

  • Afinally或上下文管理器或atexit确保在关闭时保存文件,即使遇到异常或 ^C。
  • 一个经常保存它们的计时器。
  • 缓存对象上的钩子以在每次更新或每次第 N 次更新时保存。(只需覆盖该__setitem__方法 - 或者如果您使用更高级的类之一而不是字典,请参阅扩展缓存类以了解您可以做的其他事情。)

或者您甚至可以使用磁盘上的键值数据库作为缓存。

最简单的此类数据库是dbm. 它仅限于str/bytes键和值。(shelve如果你想要非字符串值,你可以使用;如果你想要非字符串键,你可能需要一个不同的解决方案。)所以,这对我们的例子不太适用。但对于一个类似的例子,它几乎是神奇的:

import dbm
import time
import cachetools

cache = dbm.open('mycache.dbm', 'c')
@cachetools.cached(cache, key=lambda s:s)
def find_string_sum(s):
    time.sleep(5)
    return s + '!'

print(find_string_sum('a'))
print(find_string_sum('b'))
print(find_string_sum('a'))
Run Code Online (Sandbox Code Playgroud)

唯一棘手的一点是我必须覆盖该key函数。(默认的键函数处理*args, **kw,因此对于参数,'a'您最终会得到类似(('a',), ()),这显然不是字符串。)


1. 正如您从源代码中看到,有一些错误修复以确保所有类在所有受支持的 Python 版本中都可以选择,因此这显然是故意的。