这个看似简单的TTL缓存访问模式的bug在哪里?

问题描述 投票:0回答:1

遇到一个问题。我将使用 python 显示代码片段:

from cachetools import TTLCache

cache = TTLCache(maxsize=SOME_SIZE, ttl=SOME_TTL)

def fetch(key):
  if key not in cache:
    result = database.get_result(key)
    cache[key] = result
  result = cache[key]
  return result

这是我制作的一个简单的访问模式,我将一些结果缓存在 TTL 缓存中。但在某些边缘情况下,我会从缓存中收到关键错误。不知怎的,它在那之前就过期了。怎么会发生这种事呢?如果缓存中没有,我就将其放入缓存中并立即使用它。否则,我从缓存中获取并使用它。我也使用 5 分钟 TTL。好奇我可能在哪里遇到一些垃圾收集或边缘情况?

编辑:改进变量名称以提高问题的可读性。

python caching ttl
1个回答
1
投票

有可能,在“检查项目是否在缓存中”和“从缓存中获取项目”之间的时间里,该项目实际上可能已从缓存中删除

无需查看

TTLCache
的代码,并且考虑到 Python 通常的顺序处理,只有当您满足以下任一条件时,这种情况才可能发生:

  • 运行真实线程;或
  • 如果
    cache[key]
    调用在尝试查找并返回旧缓存条目之前清除了旧缓存条目。

但是,事实上,查看代码后,它使用了上面第二点的变体。每当缓存一个项目时,都会根据当前时间加上生存时间给出一个到期时间。

然后

__contains__
(对于
in
)和
__getitem__
(对于
[]
)dunder 函数都会检查此项以查看该项目是否已过期并应从缓存中删除。

因此,如果当您检查密钥是否存在时,当前时间是在到期时间之前,但是当您尝试检索时,当前时间是在到期时间之后,则可以轻松解释偶尔出现的边缘情况。 遇到这些情况,通常的做法是“寻求宽恕而不是请求许可”。这将需要尝试获取缓存的条目,并且只有在出现错误时,才获取实际值并重新缓存它,类似于:

def fetch(key): try: result = cache[key] except KeyError: result = db.get_value(key) cache[key] = result return result

© www.soinside.com 2019 - 2024. All rights reserved.