2012-09-11 66 views
0

我寫了一個函數來修改傳入的字典。但是,當我使用多處理模塊對代碼進行並行處理時,它在串行運行時表現出不同的行爲。字典沒有被修改。使用多處理混亂修改傳入對象

下面附上的是我的問題的玩具示例。當使用map_async運行時,字典未被修改,但在for循環中運行時被修改。感謝您澄清我的困惑!

#!/usr/bin/env python 

from multiprocessing import Pool 

def main1(x): 
    x['a'] = 1 
    print x 

    return 1 

def main2(x): 
    x['b'] = 2 
    print x 

p = Pool(2) 
d = {1:{}, 2:{}} 
r = p.map_async(main1, d.values()) 
print r.get() 
print "main1", d 

for x in d.values(): 
    main2(x) 

print "main2", d 
+1

我試着運行你的代碼,它填滿了我的內存並使我的電腦崩潰。大聲笑。我在一臺win7機器上,我假設你在Linux上? – Onlyjus

+0

@Onlyjus是的,我在OSX上運行這個。對於那個很抱歉!我沒有包含一個'if __name__ =='__main __'',這顯然[在Windows中會導致意外的副作用](http://docs.python.org/library/multiprocessing.html#multiprocessing-programming)。 – user449511

+0

是的,這將做到這一點。 – Onlyjus

回答

1

r = p.map_async(main1, d.values())做到這一點:

1)評估d.values() - 這是[{}, {}]
2)在該列表中執行main1(item)每個項目上的工人從池中
3)收集結果從這些電話到一個清單 - [1, 1] - 因爲這是什麼main1返回
4)將該列表分配到r

因此,它確實具有內置函數map()的功能,但採用並行方式。

這意味着,你的字典d從來沒有使它成爲任何工作進程,因爲它不是則傳遞到map_async,因此main1d參考。

而且,即使您通過參考d - 由於@羅蘭史密斯所解釋的原因,它也不起作用。

重點是:你不應該首先修改字典。在傳統編程中,即使可以修改參數,它的功能也不是很好。對於並行編程,它絕對是至關重要的以遵循功能編程風格,在這種情況下意味着:

函數應對其輸入執行計算,並返回進一步處理的結果。

功能地圖減少是在功能的編程很常見的,並組合它們一起形成一種適於非常好用於分佈式計算的圖案。從MapReduce維基百科的文章:

「地圖」一步:主節點獲取輸入,其劃分成更小的 子問題,並把它們分配給工作節點。工作節點可能會再次這樣做,從而導致多級樹形結構。 工作節點處理較小的問題,並將答案傳回 到其主節點。

「減少」一步:主節點,然後收集你所有的 子問題,並結合它們以某種方式形成輸出 - 答案,它最初試圖解決的問題。

因此,爲了有效地並行化您的程序,有助於嘗試根據這些功能來思考您的問題。

有關具體示例,請參閱IEEE Spectrum中的文章The Trouble With Multicore。它描述了一個method of parallelizing the computation of PI,可以很容易地使用map/reduce來實現。

+0

感謝您的澄清!我最初編寫它是爲了傳遞數據,但字典很大,所以我想修改它,似乎我不得不重新考慮我的程序結構。 – user449511

+1

@ user449511我更詳細地回答了一些關於map/reduce的問題。 –

+0

非常感謝!我最初甚至都沒有考慮過map-reduce,但它實際上聽起來像是一個非常適合我當前的問題,並且容易擴展,如果它真的變大的話。這篇論文也很棒。 – user449511

2

您正在更改main1中的可變參數。但是,這發生在與運行池不同的過程中。他們不共享數據。

當運行map_async,蟒拷貝從每一次迭代到工作進程,然後執行相應的功能的數據,採集返回值並傳遞迴到過程運行map_async。它沒有通過任何修改的回覆。