2016-03-03 153 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