我刚刚研究了这个文档部分enter link description here
据我了解这个功能
import multiprocessing
pool = multiprocessing.Pool()
print pool.map(f, range(10))
将创建一个任务 block ,其数量等于核心数量。结果将与从序列中获取输入的顺序相同。
文档还说---将阻塞直到完成:
让我们想象上面的 f 是一个复杂的函数。我们有 4 个 CPU,因此 block 大小为 4,它是否会阻塞,直到所有 4 个都完成,然后才获取下一个 block ?
那么在最坏的情况下,3 个空闲核心会空闲很长时间,直到最后一个核心完成为止?
最佳答案
您似乎认为 chunksize
将与核心数量匹配。这是不正确的。如果未指定,chunksize
具有一个实现定义的值,并且它不等于核心数量,至少在 CPython(引用解释器)上是这样。在撰写本文时,在 Python 2.7 和 3.7 上,使用的计算为:
if chunksize is None:
chunksize, extra = divmod(len(iterable), len(self._pool) * 4)
if extra:
chunksize += 1
len(self._pool)
是工作进程的数量,len(iterable)
是输入可迭代对象中的项目数量(即 list
如果没有定义长度,则进行验证)。
因此,对于您的情况,计算结果为:
chunksize, extra = divmod(10, numcores * 4)
if extra:
chunksize += 1
对于四核机器(例如),将计算 chunksize, extra = 0, 10
,然后 if
检查将更改 chunksize
到 1
。因此,每个工作人员都会获取一个输入值(0、1、2 和 3 几乎会立即被抓取),然后当每个工作人员完成时,它会再抓取一项。假设所有项目花费的时间大致相同,您将在完全占用的情况下进行两轮(使用 4/4 个核心),然后在半占用的情况下进行一轮(使用 2/4 的核心) 。最坏的情况是最后一个开始的任务需要最长的运行时间。如果这是提前知道的,您应该尝试组织您的输入以防止这种情况发生(首先放置最昂贵的项目,因此在不完全占用的情况下运行的最终任务很短并且快速完成,从而最大化并行性);否则,这是不可避免的。
对于大量任务,是的,默认的 block 大小将会增加,例如对于四个核心上的 100 个输入,您的 chunksize
为 7
,生成 15 个 block ,其中最后一个 block 尺寸过小。所以,是的,对于运行时间差异很大的任务,您将面临占用率低的长尾风险。如果存在风险,请将您的 chunksize
显式设置为 1
;它会降低整体性能(使其更接近 imap 的性能),但它消除了一个工作线程在一个 block 中处理 7 项中的第 1 项而所有其他核心都处于空闲状态的可能性。
关于 map 上的 Python 多处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53271511/