Python多处理 - 如何有效地从地图中断?

时间:2015-10-24 12:26:23

标签: python python-3.x python-multiprocessing

突破map按预期工作:

def worker(x):
    print("worker call x=%s" % x)
    return x

for x in map(worker, range(5)):
    print(x)
    if x == 2:
        break

worker call x=0
0
worker call x=1
1
worker call x=2
2

但如果我对multiprocessing做同样的事情,我会得到这个:

from multiprocessing import Pool

pool = Pool(2)
for x in pool.map(worker, range(5)):
    print(x)
    if x == 2:
        break
pool.close()
pool.join()

0
1
2
worker call x=0
worker call x=1
worker call x=2
worker call x=3
worker call x=4

为什么多处理的地图表现不同?如何避免不必要的函数调用?

3 个答案:

答案 0 :(得分:2)

多处理的映射行为不同,因为它不像内置映射那样同步地对映射可迭代对象进行识别,它会立即将每个迭代拆分为一个单独的进程并加入结果。

如果您不熟悉并发原则,我会尝试简要地解释一下这一点。

在使用内置映射的第一个示例中,代码将创建一个可迭代对象,允许您按顺序逐个执行worker。它一次执行一个并按顺序执行的事实意味着打印worker call x=的函数将始终先打印,然后执行继续到循环内部,这将只打印x的值。这也意味着当你的循环命中2时你可以退出循环而不需要对map或循环体本身进行任何额外的调用。这是一个同步操作,一切都很有礼貌,等待轮到你执行。

在第二个示例中,使用多处理映射代码仍会创建一个处理worker(x)的可迭代对象。但是,这一次,您不是每次执行worker(x)每次调用(同步)。多处理映射调用将立即将所有映射调用发送到单独的进程以先执行,然后组合结果。然后你的循环执行组合结果,并在你指示它时再次停在2。不幸的是,所有的映射条目都已经在不同的进程中执行,所以当循环体执行的次数最少时,映射不是。

希望这有助于您了解更好的原因。

答案 1 :(得分:1)

multiprocessing.Pool的基本性质是,只要你说pool.map(...),它就会将传递的iterable中的所有任务提交给队列以供工作进程执行。一旦将这样的任务放入池中,它最终将被工作进程使用并进行处理。你对结果没有任何改变可以改变这一点。

答案 2 :(得分:1)

应该注意的是,如果您尝试使用Python2.x的第一个版本(我做过),结果将是:

worker call x=0
worker call x=1
worker call x=2
worker call x=3
worker call x=4
0
1
2

没有涉及任何多处理。

不同之处在于,在Python 2中,doc表示:

  

将函数应用于iterable的每个项目并返回结果列表...

当Python 3 doc声明:

  

返回一个迭代器,它将函数应用于每个iterable项,产生结果......

这意味着在Python 3中更改了map以返回可迭代而不是列表。

即使在Python 3中,multiprocessing.pool.Pool.map doc说:

  

map()内置函数的并行等价物(它只支持一个可迭代的参数)。 阻止,直到结果准备就绪。

(强调我的)

这意味着该方法首先通过生成多个进程来计算结果列表,然后只返回一个完整的结果对象,而不是每次子进程结束时都产生一个值。通过这种方式,它更接近Python2 map内置而不是Python3。