Python多处理-如何有效地脱离映射



脱离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

为什么多进程的映射行为不同?如何避免不必要的函数调用?

multiprocessing的map的行为不同,因为它不像内置map那样同步地读取map可迭代对象,它将每次迭代立即拆分为一个单独的进程,并将结果连接在一起。

如果你不熟悉并发原则,我将试着简单地解释一下。

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

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

希望这能帮助你更好地理解为什么

multiprocessing.Pool s的基本性质是,只要您输入pool.map(...),它就会将传递的可迭代对象中的所有任务提交给队列,供工作进程执行。一旦将这样的任务放入池中,它最终将由工作进程使用并进行处理。你对结果做什么都改变不了这一点。

应该注意的是,如果您使用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文档声明:

返回一个迭代器,对iterable的每一项应用function,产生结果…

这意味着map在Python 3中被更改为返回可迭代对象而不是列表。

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

map()内置函数的并行等效函数(但它只支持一个可迭代参数)。阻塞直到结果准备好。

(强调我的)

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

相关内容

  • 没有找到相关文章

最新更新