20

我正在使用LRU 缓存来加速一些相当繁重的处理。它运行良好并且大大加快了速度。然而...

当我多进程时,每个进程都会创建自己的单独缓存,并且同一事物有 8 个副本。这似乎不是问题,直到盒子内存不足并因此发生坏事......

理想情况下,我的应用程序只需要大约 300 个项目的缓存大小,1*300 将适合我必须使用的 7GB,但 8*300 不适合。

如何让所有进程共享同一个缓存?

4

2 回答 2

11

我相信您可以使用 aManager在进程之间共享字典。从理论上讲,这应该让您对所有功能使用相同的缓存。

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

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.

于 2012-12-04T00:33:55.757 回答
0

将共享缓存传递给每个进程。父进程可以实例化一个缓存并将其作为参数引用到每个进程...

@utils.lru_cache(maxsize=300)
def get_stuff(key):
    """This is the routine that does the stuff which can be cached.
    """
    return Stuff(key)

def process(stuff_obj):
    """This is the routine which multiple processes call to do work with that Stuff
    """
    # get_stuff(key) <-- Wrong; I was calling the cache from here
    stuff_obj.execute()

def iterate_stuff(keys):
    """This generates work for the processses.
    """
    for key in keys:
        yield get_stuff(key)  # <-- I can call the cache from the parent

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

这个例子很简单,因为我可以在调用进程之前查找缓存。某些场景可能更喜欢将指针传递给缓存而不是值。例如:

        yield (key, get_stuff)

卡特里尔让我走上了正确的道路,我会实施这个答案,但是,愚蠢的我,我的错误比他建议的更容易解决。

于 2012-12-04T00:54:53.380 回答