imap
/imap_unordered
和map
/之间有两个主要区别map_async
:
- 他们使用您传递给他们的可迭代对象的方式。
- 他们将结果返回给您的方式。
map
通过将可迭代对象转换为列表(假设它还不是列表)、将其分成块并将这些块发送到Pool
. 将 iterable 分成块比在进程之间一次传递一个 item 的 iterable 中的每个项目执行得更好——尤其是在 iterable 很大的情况下。但是,将可迭代对象转换为列表以对其进行分块可能会产生非常高的内存成本,因为整个列表都需要保存在内存中。
imap
不会将您提供的可迭代对象变成列表,也不会将其分成块(默认情况下)。它将一次迭代一个可迭代的元素,并将它们每个发送到一个工作进程。这意味着您不会将整个可迭代对象转换为列表而对内存造成影响,但这也意味着大型可迭代对象的性能较慢,因为缺少分块。然而,这可以通过传递一个chunksize
大于默认值 1 的参数来缓解。
imap
/imap_unordered
和map
/之间的另一个主要区别map_async
是,使用imap
/ imap_unordered
,您可以在工作人员准备好后立即开始接收结果,而不必等待所有工作人员完成。使用map_async
, anAsyncResult
会立即返回,但在所有结果都被处理之前,您实际上无法从该对象中检索结果,此时它返回的列表map
与(map
实际上在内部实现为map_async(...).get()
)相同。没有办法得到部分结果;您要么拥有全部结果,要么一无所有。
imap
并且imap_unordered
都立即返回可迭代对象。使用imap
,结果将在准备好后立即从可迭代中产生,同时仍保留输入可迭代的顺序。使用imap_unordered
,结果将在它们准备好后立即产生,而不管输入可迭代的顺序如何。所以,假设你有这个:
import multiprocessing
import time
def func(x):
time.sleep(x)
return x + 2
if __name__ == "__main__":
p = multiprocessing.Pool()
start = time.time()
for x in p.imap(func, [1,5,3]):
print("{} (Time elapsed: {}s)".format(x, int(time.time() - start)))
这将输出:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
如果你使用p.imap_unordered
而不是p.imap
,你会看到:
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
如果你使用p.map
or p.map_async().get()
,你会看到:
3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
imap
因此,使用/ imap_unordered
over的主要原因map_async
是:
- 您的可迭代对象足够大,以至于将其转换为列表会导致您耗尽/使用太多内存。
- 您希望能够在所有结果完成之前开始处理结果。