2013-02-06 73 views
0

標準memoize裝飾器中的緩存是否處理安全?是一個蟒蛇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值。 也許緩存不共享,畢竟?如果不共享,如果有一個流程安全的方式共享它(以節省更多的計算),我會創建 。

回答

0

默認情況下,Python中的多進程程序在進程間共享的很少。共享的幾件事是pickled,它有自己的一些限制。您示例中的fib函數名義上共享,但pickle按名稱存儲函數,而不是按值存儲。這就是爲什麼它的緩存不能共享。

如果你想爲你的memoize修飾器有一個同步緩存,你需要添加一個同步,比如multiprocessing.Queuemultiprocessing.Array。這可能比簡單地讓每個進程重新計算值都要慢,因爲它會在進程來回傳遞更新時引入大量開銷。另外,如果您不需要單獨的進程在運行時緊密同步,您可以想出一種在進程啓動和停止時將緩存傳遞到進程或從進程傳遞進程的方法(例如,使用額外的參數和返回值),這樣順序調用可以從記憶中受益,即使並行調用沒有。