5

下面是一個完整簡單的工作示例Optimzing multiprocessing.Pool昂貴的初始化

import multiprocessing as mp 
import time 
import random 


class Foo: 
    def __init__(self): 
     # some expensive set up function in the real code 
     self.x = 2 
     print('initializing') 

    def run(self, y): 
     time.sleep(random.random()/10.) 
     return self.x + y 


def f(y): 
    foo = Foo() 
    return foo.run(y) 


def main(): 
    pool = mp.Pool(4) 
    for result in pool.map(f, range(10)): 
     print(result) 
    pool.close() 
    pool.join() 


if __name__ == '__main__': 
    main() 

如何修改它,以便美孚僅由每個工人,不是每一個任務初始化一次?基本上我想在init稱爲4倍,而不是10。我使用Python 3.5

+0

如果該類初始化一次,然後複製到每個工作人員,會好嗎? –

+0

@BrendanAbel我認爲是。那意味着對象必須是可以醃製的?該對象在初始化後永遠不會發生變化,所以我不知道爲什麼複製會很糟糕。 – user2133814

+0

多處理與多線程不同。他們有很大不同的特點。 – jpmc26

回答

6

預期的方式來處理這樣的事情是通過可選的initializerinitargs參數到Pool()構造函數。它們的存在正是爲了讓您在創建工作進程時精確地執行一次任務。因此,例如添加:

def init(): 
    global foo 
    foo = Foo() 

,改變Pool創建於:

pool = mp.Pool(4, initializer=init) 

如果你需要傳遞參數給你的每個進程初始化函數,那麼你也想加入適量initargs=...論據。

注:當然,你也應該從f()刪除

foo = Foo() 

線,讓你的函數使用init()創建全球foo

+0

您能否在此解釋全局關鍵字。我在文檔中看到了初始化器,但沒有想到/瞭解「全局」,所以我沒有看到如何使其工作。謝謝 – user2133814

+0

剛纔看到我的編輯:您還需要使用由初始化函數創建的'foo'。初始化函數運行一次並結束,因此它所做的任何更改都必須在全局範圍內可見,以便稍後使用其他函數(例如'map()'調用)可以受益。 –

+1

。沒有任何內容在進程間共享。自從第1天開始,'global'就已經開始使用Python了,多年前'multiprocessing'甚至是一個模塊的想法。 'global'與進程(或線程)無關。在上下文中,它只是告訴'init()'在模塊的全局範圍內而不是在(默認的)'init'的本地範圍內綁定'foo'。在多處理中,每個進程都有自己獨特的模塊全局名稱空間。 –

2

最爲明顯,延遲加載

_foo = None 
def f(y): 
    global _foo 
    if not _foo: 
     _foo = Foo() 
    return _foo.run(y) 
+1

混淆爲什麼你有一個從未被引用的全局'_foo'? – Bakuriu