【问题标题】:Is there a Python caching library?有 Python 缓存库吗?
【发布时间】:2010-11-28 11:23:28
【问题描述】:

我正在寻找 Python 缓存库,但目前找不到任何东西。我需要一个简单的dict-like 界面,我可以在其中设置密钥及其到期时间并将它们重新缓存。有点像:

cache.get(myfunction, duration=300)

如果它存在,它将给我缓存中的项目,或者如果它不存在或已过期,则调用该函数并存储它。有人知道这样的事情吗?

【问题讨论】:

  • 我认为您的示例中缺少item
  • 是的,这可能需要一个密钥...而且,2.x.
  • 同一进程内还是进程间共享?螺纹与否?
  • 它应该是线程安全的,对不起,我应该提到的。我不需要在进程之间共享。
  • 试试DiskCache:Apache2 许可、100% 覆盖、线程安全、进程安全、多重驱逐策略和fast (benchmarks)

标签: python caching


【解决方案1】:

从 Python 3.2 开始,您可以使用 functools 库中的装饰器 @lru_cache。 这是一个最近使用的缓存,因此其中的项目没有过期时间,但作为快速破解它非常有用。

from functools import lru_cache

@lru_cache(maxsize=256)
def f(x):
  return x*x

for x in range(20):
  print f(x)
for x in range(20):
  print f(x)

【讨论】:

  • cachetools 提供了一个很好的实现,它兼容 python 2 和 python 3。
  • cachetools 的大 +1... 看起来很酷,并且有更多的缓存算法 :)
  • 这不应该被建议!保持兼容。
  • @roboslone,两年(减去 4 天..)从您关于线程不安全的评论开始,它可能已经改变。我有 cachetools 2.0.0,我在代码中看到它使用 RLock。 /usr/lib/python2.7/site-packages/cachetools/func.py
  • @Motty:cachetools 4.0.0.0 的documentation 说:“请注意所有这些类都不是线程安全的。从多个线程必须正确同步,例如通过使用具有合适的 lock 对象的记忆装饰器之一“(我的粗体)
【解决方案2】:

【讨论】:

  • 啊,我一直在寻找这个,我发现的只是一个 wiki,上面提到了如何将它用作 WSGI 中间件。好像是我需要的,谢谢。
  • 另见dogpile- 据说是新的和改进的烧杯。
【解决方案3】:

您还可以查看Memoize decorator。您可能无需太多修改就可以让它做您想做的事情。

【讨论】:

  • 这很聪明。一些更改,装饰器甚至可能在设定的时间后过期。
  • 您绝对可以将基于空间的限制写入装饰器中的缓存。例如,如果您想要一个函数来逐项生成斐波那契数列,那将很有帮助。您想要缓存,但您只需要最后两个值 - 保存所有这些值只是空间效率低下。
【解决方案4】:

还没有人提到搁置。 https://docs.python.org/2/library/shelve.html

它不是 memcached,但看起来更简单,可能适合您的需要。

【讨论】:

  • 我为标准搁置模块(包括一个用于缓存 http 请求的辅助函数)编写了一个线程和多进程安全的包装器,以防对任何人有用:github.com/cristoper/shelfcache
【解决方案5】:

Joblib https://joblib.readthedocs.io 支持 Memoize 模式中的缓存功能。大多数情况下,这个想法是缓存计算量大的函数。

>>> from joblib import Memory
>>> mem = Memory(cachedir='/tmp/joblib')
>>> import numpy as np
>>> square = mem.cache(np.square)
>>> 
>>> a = np.vander(np.arange(3)).astype(np.float)
>>> b = square(a)                                   
________________________________________________________________________________
[Memory] Calling square...
square(array([[ 0.,  0.,  1.],
       [ 1.,  1.,  1.],
       [ 4.,  2.,  1.]]))
___________________________________________________________square - 0...s, 0.0min

>>> c = square(a)

你也可以做一些花哨的事情,比如在函数上使用 @memory.cache 装饰器。文档在这里:https://joblib.readthedocs.io/en/latest/generated/joblib.Memory.html

【讨论】:

  • 附带说明一下,当您使用大型 NumPy 数组时,joblib 真的很出色,因为它有专门处理它们的特殊方法。
【解决方案6】:

我认为the python memcached API是流行的工具,但我自己没有使用过,不确定它是否支持你需要的功能。

【讨论】:

  • 这是行业标准,但我想要的只是一个简单的内存存储机制,可以容纳 100 个左右的键,而 memcached 有点矫枉过正。不过,谢谢你的回答。
【解决方案7】:
import time

class CachedItem(object):
    def __init__(self, key, value, duration=60):
        self.key = key
        self.value = value
        self.duration = duration
        self.timeStamp = time.time()

    def __repr__(self):
        return '<CachedItem {%s:%s} expires at: %s>' % (self.key, self.value, time.time() + self.duration)

class CachedDict(dict):

    def get(self, key, fn, duration):
        if key not in self \
            or self[key].timeStamp + self[key].duration < time.time():
                print 'adding new value'
                o = fn(key)
                self[key] = CachedItem(key, o, duration)
        else:
            print 'loading from cache'

        return self[key].value



if __name__ == '__main__':

    fn = lambda key: 'value of %s  is None' % key

    ci = CachedItem('a', 12)
    print ci 
    cd = CachedDict()
    print cd.get('a', fn, 5)
    time.sleep(2)
    print cd.get('a', fn, 6)
    print cd.get('b', fn, 6)
    time.sleep(2)
    print cd.get('a', fn, 7)
    print cd.get('b', fn, 7)

【讨论】:

  • 我做了类似的事情,但是你需要多线程的锁和一个大小参数来避免它无限增长。然后你需要一些函数来按访问对键进行排序,以丢弃最少访问的键等等......
  • repr 行不正确(应使用 self.timeStamp)。这也是一个糟糕的实现,不需要为每个 get() 进行数学运算。过期时间应在 CachedItem init 中计算。
  • 其实,如果你只是实现get方法,这不应该是dict子类,应该是嵌入了dict的对象。
【解决方案8】:

您可以使用我的简单解决方案来解决问题。这真的很简单,没有什么花哨的:

class MemCache(dict):
    def __init__(self, fn):
        dict.__init__(self)
        self.__fn = fn

    def __getitem__(self, item):
        if item not in self:
            dict.__setitem__(self, item, self.__fn(item))
        return dict.__getitem__(self, item)

mc = MemCache(lambda x: x*x)

for x in xrange(10):
    print mc[x]

for x in xrange(10):
    print mc[x]

它确实缺少过期功能,但是您可以通过在 MemCache c-tor 中指定特定规则来轻松扩展它。

希望代码足够不言自明,但如果不是,请提一下,该缓存将作为其 c-tor 参数之一传递给翻译函数。它又用于生成有关输入的缓存输出。

希望对你有帮助

【讨论】:

  • +1 用于提出简单的建议。根据问题,它可能只是工作的工具。附言你不需要else 中的__getitem__ :)
  • 他为什么不需要else__getitem__ 中?这就是他填充字典的地方......
【解决方案9】:

试试 redis,它是应用程序以原子方式共享数据或拥有一些 Web 服务器平台时最简洁、最简单的解决方案之一。它很容易设置,你需要一个python redis客户端http://pypi.python.org/pypi/redis

【讨论】:

  • 应该提一下,进程外,需要使用TCP访问。
【解决方案10】:

在pypi上查看gocept.cache,管理超时。

【讨论】:

    【解决方案11】:

    project 旨在提供“人类缓存” (不过好像还不太清楚)

    来自项目页面的一些信息:

    安装

    pip 安装缓存

    用法:

    import pylibmc
    from cache import Cache
    
    backend = pylibmc.Client(["127.0.0.1"])
    
    cache = Cache(backend)
    
    @cache("mykey")
    def some_expensive_method():
        sleep(10)
        return 42
    
    # writes 42 to the cache
    some_expensive_method()
    
    # reads 42 from the cache
    some_expensive_method()
    
    # re-calculates and writes 42 to the cache
    some_expensive_method.refresh()
    
    # get the cached value or throw an error
    # (unless default= was passed to @cache(...))
    some_expensive_method.cached()
    

    【讨论】:

      【解决方案12】:

      查看 bda.cache http://pypi.python.org/pypi/bda.cache - 使用 ZCA 并使用 zope 和 bfg 进行测试。

      【讨论】:

        【解决方案13】:

        ExpiringDict 是另一种选择:

        https://pypi.org/project/expiringdict/

        【讨论】:

          【解决方案14】:

          keyring 是最好的 python 缓存库。你可以使用

          keyring.set_password("service","jsonkey",json_res)
          
          json_res= keyring.get_password("service","jsonkey")
          
          json_res= keyring.core.delete_password("service","jsonkey")
          

          【讨论】:

          • 这是一个密钥环库,不是缓存库。
          • @StavrosKorokithakis 实际上,我通过密钥环实现了密钥缓存
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-28
          • 1970-01-01
          • 2013-04-22
          • 1970-01-01
          • 2019-08-16
          • 2010-10-23
          • 1970-01-01
          相关资源
          最近更新 更多