自制小memcache

时间:2010-10-23 14:05:53

标签: python memcached

我正在将“云”之外的Google App Engine Web应用程序移动到标准Web框架(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 :(得分:2)

在我看来,您的缓存可能会低效增长,因为它会保留很少使用的条目。因为,除非为特定密钥请求get操作,否则似乎不会删除缓存中的条目。

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

  1. 当请求Item时,我会将seconds重新启动到初始值。所以要保留系统经常使用的元素。
  2. 我会在一个单独的线程中实现一个机制来遍历缓存并删除太旧的条目。
  3. 您也可以从这个Fixed size cache

    中获得一些想法

    <强>被修改

    我刚发现这个食谱,它非常酷。基本上你可以用函数装饰器包装你想要缓存的逻辑。类似的东西:

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

    这些LRU and LFU cache decorator装饰器将为您实现缓存逻辑。最近最少使用(LRU)或最不常用(LFU)(参见Cache_algorithms以获取参考)

答案 1 :(得分:0)

  

在我的应用程序中,我只使用此缓存来存储每隔X小时从远程api检索到的一堆数据;换句话说,我并没有过多地强调这个缓存。

...

  

我怎样才能改善它?

如果您的代码适合您,为什么还要麻烦?

然而,当您明确要求提出意见时,我仍尝试添加我的想法。对我来说,听起来你可以使用像文件或数据库这样的传统存储来存储数据,因为它只是定期刷新。在许多情况下,只需要一些(可能很昂贵的)预处理,因此您可以专注于完成一次工作,只需将数据存储在一个表单中,以便快速访问/交付给客户端。

优点:

  • 简单
  • 多个流程没有问题(例如FastCGI)
  • 减少记忆足迹
  

我是否需要使其成为线程安全的?

这实际上取决于您的使用模式。但是,根据您的API,我猜这不是必需的,因为您计算两次值(最坏情况)。