我写了一个函数来修改传入的字典。但是,当我使用多处理模块并行化代码时,它在串行运行时表现出不同的行为。字典未被修改。
下面附有我的问题的玩具示例。使用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
答案 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轻松实现。