是python内存化装饰器进程安全的



标准memoize decorator进程中的缓存安全吗?

例如,假设我定义了以下装饰器:

import functools
def memoize(func):
    cache = {}
    @functools.wraps(func)
    def memoized(*args):
        result = None
        if args in cache:
            result = cache[args]
        else:
            result = func(*args)
            cache[args] = result
        return result
    return memoized

假设我正试图用它来加速递归函数的计算,比如:

@memoize
def fib(n):
    result = 1
    if n > 1:
        result = fib(n-1) + fib(n-2)
    return result

现在我想知道计算fib()的两个进程是否会发生冲突?例如:

if __name__ == "__main__":
    from multiprocessing import Process
    p1 = Process(target=fib, args=(19,))
    p2 = Process(target=fib, args=(23,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

我的第一个想法是缓存保存在fib的上下文中,因此过程之间共享,这可能会导致比赛条件。但是,我认为可能发生的最糟糕的情况是,他们都会认为,尚未计算fib(17),将继续计算并行并一个接一个地存储相同的结果-不理想,但我想并不可怕。但我仍然想知道是否有一种安全的方法。

EDIT:我在memoryed()的每个分支中添加了一个print语句,似乎每个进程都会重新计算缓存中的所有fib值。也许缓存毕竟不是共享的?如果不分享,我会如果有一种进程安全的方式来共享它(以节省更多的计算)。

默认情况下,Python中的多进程程序在进程之间共享很少。共享的少数事物是pickled,它本身也有一些局限性。示例中的fib函数名义上是共享的,但pickle按名称而非值存储函数。这就是为什么它的缓存没有被共享。

如果您想为memoize装饰器提供一个同步缓存,则需要向其添加同步,例如multiprocessing.Queuemultiprocessing.Array。不过,这可能比简单地让每个进程重新计算值要慢,因为在进程来回传递更新时会引入大量开销。

或者,如果您不需要在进程运行时对它们进行严格同步,您可以想出一种方法,在进程启动和停止时将缓存传递给进程和从进程传递缓存(例如,使用额外的参数和返回值),这样顺序调用就可以从内存化中受益,即使并行调用没有。

最新更新