这是我正在使用的代码的简化版本:我有一个带有实例方法的python类,它接受一个字符串列表并计算每个字符串的结果,最终在返回之前组合结果,如下所示:
class Foo(object):
def do_task(stringList):
for s in stringList:
result = computeResult(s)
# combine results below...
由于使用字符串的计算都是独立的(而且相当昂贵),我正在尝试将操作与多处理模块中的Pool类并行化。因此我定义了do_task
的并行版本如下(我目前只打印单独的结果而不是组合它们):
def do_task_parallel(stringList):
numProcs = 2
pool = Pool(processes=numProcs)
chunksize = int(math.ceil(len(stringList) / float(numProcs)))
for result in pool.imap(self.do_task, stringList, chunksize):
print result
pool.close()
根据我对Pool的工作原理的理解,我已经阅读了这个文档和示例,这应该将我的stringList iterable分成大小大小为chunkSize的块,每个块都作为任务提交给池中的一个进程。因此,如果我有一个列表stringList = ["foo1", "foo2", "foo3", "foo4"]
在两个进程中分开(给出2的块),则池应该将其分为stringList1 = ["foo1", "foo2"]
和stringList2 = ["foo3", "foo4"]
,这将由两个进程处理并行的不同过程。
但是,当我创建一个Foo()对象并调用foo.do_task_parallel(stringList)
时,似乎池正在将stringList
的每个元素分别传递给do_task
(作为一个块) 。这不仅不会加速我的代码,但它会使其不正确并实际上减慢它,因为do_task
然后在四个独立的每一个上传入的一个输入字符串的每个字符上调用computeResult
调用。我期待两个调用,每个调用处理一个大小为2的输入列表,而不是处理单个输入字符串的四个调用。我已经检查了chunksize
确实是2.我做错了什么?如果有帮助,我通过cygwin在Windows 7上运行python 2.7.3。
答案 0 :(得分:9)
你的理解是关闭的;-) chunksize
纯粹是一个可选的优化:它改变 nothing 关于传递给工作者函数的内容,它只给出{{1}的提示关于一次通过内部进程间管道发送多少任务的机制。
如果您希望传递一个字符串列表,那么您必须显式地对其进行编码。例如,为了清楚起见,将其粘贴在多行上:
multiprocessing
答案 1 :(得分:2)
Pool.map
和Pool.imap
的设计与内置Python函数map
等效(并行)。因此,他们将您为其提供的功能单独应用于输入中的每个项目。
chunksize
处理项目如何被阻止到多处理任务,但不影响在各个项目上调用该函数的方式。 (基本上,对于map / imap,任务处理程序已经内置了for item in input: ...
。)
看起来你真正想做的就是通过并行地图绘制computeResult
来电,然后在获得结果后进行合并。