自制微型Memcache

5 投票
2 回答
519 浏览
提问于 2025-04-16 05:58

我正在把一个Google App Engine的网页应用迁移到一个标准的网页框架(webpy),我想知道怎么在这个新环境中实现一个类似于Gae上可用的memcache的功能。

在我的应用中,我只是用这个缓存来存储每隔X小时从远程API获取的一些数据;换句话说,我并没有过度使用这个缓存。

我简单地实现了类似这样的代码:

class TinyCache():
    class _Container():
        def __init__(self, value, seconds):
            self.value = value
            self.cache_age = datetime.now()
            self.cache_time = timedelta(seconds = seconds)
        def is_stale(self):
            return self.cache_age + self.cache_time < datetime.now() 

    def __init__(self):
        self.dict_cache={}

    def add(self, key, value, seconds = 7200):
        self.dict_cache[key] = self._Container(value, seconds)

    def get(self, key):
        if key in self.dict_cache:
            if self.dict_cache[key].is_stale():
                del self.dict_cache[key]
                return None
            else:
                return self.dict_cache[key].value
        else:
            return None

一个典型的使用方式是:

data = tinycache.get("remote_api_data")
if data is not None:
    return data
else:
    data = self.api_call()
    tinycache.add("remote_api_data", data, 7200)
    return data

我该如何改进它呢?
我需要让它线程安全吗?

2 个回答

0

在我的应用程序中,我只是用这个缓存来存储每隔一段时间从远程API获取的一堆数据;换句话说,我并没有过于依赖这个缓存。

我该如何改进它呢?

如果你的代码对你来说有效,那何必去烦恼呢?

不过,既然你明确要求我给点建议,我还是试着分享我的想法。听起来你可以考虑使用传统的存储方式,比如文件或者数据库,因为这些数据只是定期更新。在很多情况下,你可能只需要进行一些(可能比较耗时的)预处理,这样你就可以专注于一次性完成这些工作,然后把数据存储成一种方便快速访问的形式。

优点:

  • 简单
  • 不会出现多个进程之间的问题(比如FastCGI)
  • 减少内存占用

我需要让它线程安全吗?

这真的要看你是怎么使用的。不过根据你的API,我猜这并不是特别必要,因为你可能会在最坏的情况下计算一个值两次。

2

我觉得你的缓存可能会变得不太有效,因为它会保留一些很少使用的条目。因为看起来,只有在请求特定键的get操作时,缓存中的条目才会被删除。

如果你想改善你的缓存,我建议你添加以下两个简单的功能:

  1. 当请求一个项目时,我会把seconds重置为初始值。这样可以保留系统经常使用的元素。
  2. 我会在一个单独的线程中实现一个机制,遍历缓存并删除那些太旧的条目。

你也可以从这个 固定大小缓存 中获取一些灵感。

编辑

我刚发现这个方法,真是太酷了。基本上,你可以用函数装饰器来封装你想要缓存的逻辑。类似于:

@lru_cache(maxsize=20)
def my_expensive_function(x, y):
    # my expensive logic here
    return result

这些 LRU 和 LFU 缓存装饰器 会为你实现缓存逻辑。最近最少使用(LRU)或最少频繁使用(LFU)(有关这些的参考,请查看 缓存算法)。

撰写回答