2016-03-03 158 views
3

我試圖將關鍵字參數傳遞給Python的multiprocessing.Pool實例中的map函數。使用帶有關鍵字參數的multiprocessing.Pool.map()函數?

Using map() function with keyword arguments推斷,我知道我可以使用functools.partial()如下列:

from multiprocessing import Pool 
from functools import partial 
import sys 

# Function to multiprocess 
def func(a, b, c, d): 
    print(a * (b + 2 * c - d)) 
    sys.stdout.flush() 

if __name__ == '__main__': 
    p = Pool(2) 
    # Now, I try to call func(a, b, c, d) for 10 different a values, 
    # but the same b, c, d values passed in as keyword arguments 
    a_iter = range(10) 
    kwargs = {'b': 1, 'c': 2, 'd': 3} 

    mapfunc = partial(func, **kwargs) 
    p.map(mapfunc, a_iter) 

輸出是正確的:

0 
2 
4 
6 
8 
10 
12 
14 
16 
18 

這是最好的做法(最 「Python的」 方式)這樣做?我覺得:

1)Pool是常用的;

2)關鍵字參數是常用的;

3)但是,像我上面的例子一樣的組合使用有點像一個「哈克」的方式來實現這一點。

+1

對我來說似乎很好。 map只需要位置參數,所以使用partial來創建合適的函數對象是非常合理的。 – nneonneo

回答

1

如果默認參數很大,則使用partial可能不是最理想的。傳遞給map的函數在發送給工作人員(對於迭代中的每個參數一次)時重複爲pickle;通過發送合格的名稱(因爲在另一側定義相同的功能而不需要傳輸任何數據),全球Python功能(本質上)是pickle-0123作爲該功能的pickle,並且所有提供的功能都是參數。

如果kwargs是所有的小原語,就像在你的例子中一樣,這並不重要;沿着額外參數發送的增量成本是微不足道的。但是如果kwargs很大,比如說kwargs = {'b': [1] * 10000, 'c': [2] * 20000, 'd': [3]*30000},這是一個討厭的價格。

在這種情況下,你有一些選擇:那就像partial全球一級

  1. 推出自己的功能,但pickle不同的方式過:

    class func_a_only(a): 
        return func(a, 1, 2, 3) 
    
  2. 使用initializer參數到Pool,因此每個工作進程設置一次狀態,而不是每個任務一次,這樣即使您在基於spawn的環境(例如Windows)中工作,也可以確保數據可用

  3. 使用Manager s到所有進程

,可能其他方法了一把之間共享數據的一個副本。要點是,partial適用於不會產生巨大pickle的參數,但如果綁定的參數很大,它可能會殺死您。

注:在這種特殊情況下,如果你在Python 3.3+的時候,你實際上並不需要partial,並避免dict贊成tuple S保存開銷的瑣碎量。如果沒有添加任何新功能,只是一些進口的,你可以更換:

kwargs = {'b': 1, 'c': 2, 'd': 3} 
mapfunc = partial(func, **kwargs) 
p.map(mapfunc, a_iter) 

有:

from itertools import repeat 

p.starmap(func, zip(a_iter, repeat(1), repeat(2), repeat(3))) 

來達到類似的效果。要清楚的是,partial這個「修復」沒有錯(兩種方法在酸洗大物體時都會遇到同樣的問題),這只是一種偶爾有用的替代方法。

+0

謝謝你的回答!當你提到我不需要在Python> = 3.3中使用'partial'時,我不需要避免使用元組來支持元組,你的意思是我可以使用'Pool.apply_async()'而不是?我假設如果我使用'Pool.map()',我只能使用像元組或列表('pool.map(func,iterable)')的迭代器,並且不能使用字典('pool.apply_async(func ,args,kwargs)')。我是否正確? –

+0

@ShawnWang:我指的是能夠使用'Pool.starmap'而不是'Pool.map',允許您使用'zip'來構造'starmap'解包給你的'tuple'參數。這個選擇是我在最後的代碼塊中展示的,通過使用'repeat'和'zip'構造位置參數的完整集合並在位置上提供'b','c'和'd'的重複值,而不是使用關鍵字參數。 – ShadowRanger