【问题标题】:is a python memoize decorator process-safe?python memoize 装饰器过程安全吗?
【发布时间】:2013-02-06 23:07:06
【问题描述】:

标准 memoize 装饰器中的缓存是否安全?

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

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) 尚未计算,将继续计算 并行并一个接一个地存储相同的结果-不理想, 但并不可怕,我猜。但我仍然想知道是否有办法以流程安全的方式进行。

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

【问题讨论】:

    标签: python-2.7 multiprocessing decorator memoization


    【解决方案1】:

    默认情况下,Python 中的多进程程序在进程之间共享很少。共享的少数内容是pickled,它有其自身的一些限制。您示例中的 fib 函数名义上是共享的,但 pickle 按名称而不是值存储函数。这就是它的缓存不被共享的原因。

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

    或者,如果您不需要单独的进程在运行时紧密同步,您可以想出一种在进程启动和停止时将缓存传入和传出进程的方法(例如,使用额外的参数和返回值),因此顺序调用可以从记忆中受益,即使并行调用没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-15
      • 1970-01-01
      • 2012-01-15
      • 2015-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多