【发布时间】:2021-05-24 17:14:56
【问题描述】:
我想对某些数据进行多次转换。我想我可以使用多个Pool.imap,因为每个转换都只是一个简单的映射。而Pool.imap 是惰性的,所以它只在需要时进行计算。
但奇怪的是,看起来多个连续的Pool.imap 正在阻塞。而且不懒惰。以下面的代码为例。
import time
from multiprocessing import Pool
def slow(n):
time.sleep(0.01)
return n*n
for i in [10, 100, 1000]:
with Pool() as p:
numbers = range(i)
iter1 = p.imap(slow, numbers)
iter2 = p.imap(slow, iter1)
start = time.perf_counter()
next(iter2)
print(i, time.perf_counter() - start)
# Prints
# 10 0.0327413540071575
# 100 0.27094774100987706
# 1000 2.6275791430089157
如您所见,第一个元素的时间正在增加。我的机器上有 4 个内核,因此处理 1000 个项目大约需要 2.5 秒,延迟为 0.01 秒。因此,我认为两个连续的Pool.imap 正在阻塞。并且第一个 Pool.imap 在第二个开始之前完成了整个工作负载。那不是懒惰。
我做了一些额外的研究。我使用进程池还是线程池都没有关系。 Pool.imap 和 Pool.imap_unordered 会发生这种情况。当我做第三个Pool.imap 时,阻塞需要更长的时间。单个Pool.imap 不会阻塞。这个bug report 似乎相关但不同。
【问题讨论】:
-
0.01s的工作量对于一个进程来说效率不是很高。大多数 CPU 资源将用于操作系统创建和清理进程。
-
我知道。它也发生在线程上。或者当睡眠时间更长时。
-
我不太明白您期望的其他行为。
Pool的意义在于你有一些工作人员在处理你的任务——首先提交iter1意味着池也首先处理它。Pool不知道您是否、何时或以什么顺序期望结果,只知道您提交的顺序。 -
因为
imap应该是懒惰的。 IE。只在需要的时候工作。或者至少在所有其他工作完成之前完成已完成的工作。使用连续的imap打破了这种模式。 -
imap 是懒惰的,因为您可以在最后一个结果准备好之前获得第一个结果。它仍然会立即开始处理 - 如果处理与迭代步调一致,那将破坏并行化的目的。