2012-12-03 101 views
4

我正在使用缓存over here来加速一些相当重的处理。 lru_cache可以很好地工作,并且可以大大加快速度。但是,当我多进程每个进程创建它自己的单独缓存,并且有8份相同的东西。这似乎没有问题,直到盒子内存不足,结果发生坏事。理想情况下,我需要为这个应用程序缓存300个左右,但8 * 300不适合我必须使用的7GB,而我认为1 * 300会。如何共享缓存?

是否有所有进程的方式来共享同一缓存?

+0

Python的'multiprocessing'模块对[共享流程之间的状态(一部分http://docs.python.org/2/library/ multiprocessing.html#共享状态之间的处理)。 –

+0

是一个进程外缓存的选项吗?你可以在你的缓存状态中使用pickle,并将它存储在redis中吗? – SingleNegationElimination

+0

@sam事实上,看起来'经理'可以共享一个'dict',我猜想这是lfu缓存在内部。我想我希望有人已经砍死那之前,以适应这个问题,所以我没有;-) –

回答

4

我相信你可以使用一个Manager进程之间共享的字典。理论上应该可以为所有函数使用相同的缓存。

然而,我认为一个更理智的逻辑是让一个进程通过在查询缓存中查找它们来响应查询,如果它们不存在,则将该工作委托给子进程,然后缓存结果返回它。你可以很容易地做到这一点与

with concurrent.futures.ProcessPoolExecutor() as e: 
    @functools.lru_cache 
    def work(*args, **kwargs): 
     return e.submit(slow_work, *args, **kwargs) 

注意work返回Future对象,消费者将不得不等待。 lru_cache将缓存未来的对象,以便它们自动返回;我相信您可以不止一次访问他们的数据,但现在无法对其进行测试。

如果您不使用Python 3,则必须安装concurrent.futuresfunctools.lru_cache的backported版本。

0

Doh。 Katrie的把我在正确的轨道上,我会实现这个问题的答案,但我傻,它甚至比实际更容易[此应用]:

父进程可以实例化对象(从它的中央缓存)和通obj实例入池处理作为它的参数...

@utils.lru_cache(maxsize=300) 
def get_stuff(key): 
    return Stuff(key) 

def iterate_stuff(keys): 
    for key in keys: 
     yield get_stuff(key) # doh, rather than just yielding the key, yield the cached obj 

def process(stuff_obj): 
    # get_stuff(key) <-- do this in the parent, rather than the child. 
    stuff_obj.execute() 

def main(): 
    ... 
    keys = get_list_of_keys() 
    for result in pool.imap(process, iterate_stuff(keys)): 
     evaluate(result) 
    ...