使用多处理混淆修改传递对象

时间:2012-09-11 21:48:19

标签: python multiprocessing python-multithreading

我写了一个函数来修改传入的字典。但是,当我使用多处理模块并行化代码时,它在串行运行时表现出不同的行为。字典未被修改。

下面附有我的问题的玩具示例。使用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

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

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

所以它确实完成了内置函数map()的功能,但是以并行方式。

这意味着,您的字典d从未进入任何工作进程,因为它不是d的引用,而是map_async,因此main1

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

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

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

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

  

“映射”步骤:主节点接受输入,将其划分为更小   子问题,并将它们分发给工作节点。工作节点可以   依次执行此操作,从而实现多级树结构。该   工作节点处理较小的问题,并将答案传回   到它的主节点。

     

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

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

有关非常具体的示例,请参阅IEEE Spectrum中的文章The Trouble With Multicore。它描述了一个method of parallelizing the computation of PI,可以通过map / reduce轻松实现。