【问题标题】:How to use LRU caching on disk with klepto?如何通过 klepto 在磁盘上使用 LRU 缓存?
【发布时间】:2015-08-18 19:37:46
【问题描述】:

我正在尝试使用 klepto 进行 LRU 缓存。我想将缓存存储到磁盘,并且目前正在为此使用 klepto 的 dir_archive 选项。我编写了以下代码,主要基于 klepto 测试脚本中的代码:

def mymap(data):
    return hashlib.sha256(data).hexdigest()

class MyLRUCache:
    @lru_cache(cache=dir_archive(cached=False), keymap=mymap, ignore='self', maxsize=5)
    def __call__(self, data)
        return data

    call = __call__

    def store(self, data):
        self.call(data)

    # I would also appreciate a better way to do this, if possible.
    def lookup(self, key):
        return self.call.__cache__()[key]

在缓存到达maxsize 之前,此代码似乎可以正常工作。此时,lru_cache 将清除整个缓存,而不是使用 LRU 删除单个项目!以下是执行此操作的 klepto 源代码 (https://github.com/uqfoundation/klepto/blob/master/klepto/safe.py):

# purge cache
if _len(cache) > maxsize:
    if cache.archived():
        cache.dump()
        cache.clear() 
        queue.clear()
        refcount.clear()
     else: # purge least recently used cache entry
        key = queue_popleft()
        refcount[key] -= 1
        while refcount[key]:
            key = queue_popleft()
            refcount[key] -= 1
        del cache[key], refcount[key]

所以我的问题是,为什么 klepto 会清除“存档”缓存? lru_cachedir_archive可以同时使用吗?

另外,如果我的代码看起来完全疯了,我真的很感谢我应该编写这个的一些示例代码,因为没有太多关于 klepto 的文档。

附加说明: 我还尝试用cached=True 定义dir_archive。当到达maxsize 时,内存中的缓存仍然会被清除,但缓存的内容会在此时转储到归档缓存中。我有几个问题:

  1. 内存缓存仅在达到maxsize 之前是准确的,此时它被擦除。
  2. 归档缓存不受maxsize 的影响。每次内存缓存到达maxsize 时,内存缓存中的所有项目都会转储到存档缓存中,无论有多少已经存在。
  3. 根据第 1 点和第 2 点,LRU 缓存似乎是不可能的。

【问题讨论】:

  • 嗨,我是包作者。嗯……这很奇怪。我会尝试一下,看看是否可以使清除行为更具可配置性。如果您不这样做,我会将其添加为票证。
  • 所以目的是如果你选择一个已归档的缓存,缓存会转储到归档中,然后在遇到maxsize 时清除。如果您有一个未归档的缓存,它会使用 LRU 策略来清除缓存的项目(即删除并且不将它们保存在任何地方)。您似乎需要第三种选择,即当缓存命中maxsize 时,它会通过 LRU 策略转储到存档。当前未完成的原因是,如果进程阻塞,它会显着减慢计算速度(与现有方法相比)。但是,我会将其添加为选项。
  • 感谢您的帮助!

标签: klepto


【解决方案1】:

答案是在你提出问题之前你不能,但现在你可以了。 如果您从 github 获得最新的 klepto,并提供新标志 purge=False -- 然后你得到你正在寻找的行为。我刚刚添加了这个来回答你的问题。

在你的情况下:

lru_cache(cache=dir_archive(cached=False), keymap=mymap, ignore='self', maxsize=5, purge=False)

或者,例如:

@lru_cache(maxsize=3, cache=dict_archive('test'), purge=True)
def identity(x):
  return x

identity(1)
identity(2)
identity(3)
ic = identity.__cache__()
assert len(ic.keys()) == 3
assert len(ic.archive.keys()) == 0
identity(4)
assert len(ic.keys()) == 0
assert len(ic.archive.keys()) == 4
identity(5)
assert len(ic.keys()) == 1
assert len(ic.archive.keys()) == 4

@lru_cache(maxsize=3, cache=dict_archive('test'), purge=False)
def inverse(x):
  return -x

inverse(1)
inverse(2)
inverse(3)
ic = inverse.__cache__()
assert len(ic.keys()) == 3
assert len(ic.archive.keys()) == 0
inverse(4)
assert len(ic.keys()) == 3
assert len(ic.archive.keys()) == 1
inverse(5)
assert len(ic.keys()) == 3
assert len(ic.archive.keys()) == 2

如果这不符合您的预期,请添加一张票。谢谢你的建议。

【讨论】:

    猜你喜欢
    • 2018-09-10
    • 2013-08-02
    • 2014-10-21
    • 2017-07-02
    • 2015-08-18
    • 1970-01-01
    • 2023-03-26
    • 2014-07-21
    • 2014-07-03
    相关资源
    最近更新 更多