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
4

2 回答 2

2

您正在更改 中的可变参数main1。但这发生在与运行池的进程不同的进程中。他们不共享数据。

运行时map_async,python将每次迭代的数据复制到工作进程,然后工作进程执行函数,收集返回值并将其传递回正在运行的进程map_async。它不会传回任何修改后的参数。

于 2012-09-11T22:54:18.193 回答
1

r = p.map_async(main1, d.values())做这个:

1)评估d.values()- 那是[{}, {}]
2)在池中的工作人员上执行main1(item)该列表中的每个项目
3)将这些调用的结果收集到一个列表中[1, 1]- 因为这就是main1返回的内容
4)将该列表分配给r

所以它完全按照内置函数map()的方式执行,但是以并行化的方式。

这意味着,您的 dictd永远不会进入任何工作进程,因为它不是对d传递给的引用map_async,因此是main1.

即使您传递对d- 的引用,由于@Roland Smith 解释的原因,它也不起作用。

关键是:你不应该首先修改字典。即使函数可以修改参数,在传统编程中也不是很好的风格。对于并行编程,遵循函数式编程风格绝对至关重要,在这种情况下,这意味着:

函数应该对其输入进行计算,并返回进一步处理的结果。

mapreduce函数在函数式编程中非常常见,它们结合在一起形成了一种非常适合分布式计算的模式。来自关于MapReduce的维基百科文章:

“映射”步骤:主节点获取输入,将其划分为更小的子问题,并将它们分配给工作节点。工作节点可能会再次执行此操作,从而形成多级树结构。工作节点处理较小的问题,并将答案传回其主节点。

“减少”步骤:主节点然后收集所有子问题的答案,并以某种方式将它们组合以形成输出——它最初试图解决的问题的答案。

因此,为了有效地并行化您的程序,尝试根据这些功能考虑您的问题会有所帮助。

有关一个非常具体的示例,请参阅IEEE Spectrum 中的多核问题一文。它描述了一种并行化 PI 计算的方法,该方法可以很容易地用 map/reduce 实现。

于 2012-09-11T23:16:44.613 回答