自制微型Memcache
我正在把一个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
操作时,缓存中的条目才会被删除。
如果你想改善你的缓存,我建议你添加以下两个简单的功能:
- 当请求一个项目时,我会把
seconds
重置为初始值。这样可以保留系统经常使用的元素。 - 我会在一个单独的线程中实现一个机制,遍历缓存并删除那些太旧的条目。
你也可以从这个 固定大小缓存 中获取一些灵感。
编辑
我刚发现这个方法,真是太酷了。基本上,你可以用函数装饰器来封装你想要缓存的逻辑。类似于:
@lru_cache(maxsize=20)
def my_expensive_function(x, y):
# my expensive logic here
return result
这些 LRU 和 LFU 缓存装饰器 会为你实现缓存逻辑。最近最少使用(LRU)或最少频繁使用(LFU)(有关这些的参考,请查看 缓存算法)。