如何使multiprocessing.pool.map按数字顺序分发进程?

更多信息:
我有一个程序可以处理数千个数据文件,每个文件都作图。我正在使用multiprocessing.pool.map将每个文件分发到处理器,并且效果很好。有时这会花费很长时间,并且在程序运行时查看输出图像会很不错。如果映射过程按顺序分发快照,则将容易得多。相反,对于我刚刚执行的特定运行,分析的前8个快照是:0, 78, 156, 234, 312, 390, 468, 546。有没有办法使它按数字顺序更紧密地分布?

例:
这是一个示例代码,其中包含相同的关键元素,并显示出相同的基本结果:

import sys
from multiprocessing import Pool
import time

num_proc  = 4; num_calls = 20; sleeper   = 0.1

def SomeFunc(arg):
    time.sleep(sleeper)
    print "%5d" % (arg),
    sys.stdout.flush()     # otherwise doesn't print properly on single line

proc_pool = Pool(num_proc)
proc_pool.map( SomeFunc, range(num_calls) )

产量:
   0  4  2  6   1   5   3   7   8  10  12  14  13  11   9  15  16  18  17  19

回答:

来自@Hayden:使用'chunksize'参数def map(self, func, iterable, chunksize=None)

更多信息:chunksize确定一次为每个处理器分配多少次迭代。例如,我上面的示例使用的块大小为2,这意味着每个处理器都会关闭并执行该函数的2次迭代,然后返回执行更多操作(“ checkin ”)。 chunksize背后的权衡是,当处理器必须与其他处理器同步时,“检入”会产生开销-建议您要一个大块大小。另一方面,如果您有很大的块,那么一个处理器可能会完成其块,而另一个处理器可能需要很长的时间才能完成工作,因此您应该使用小块大小。我想其他有用的信息是有多少范围,每个函数调用可以花费多长时间。如果它们真的都应该花费相同的时间-使用大块数据会更有效。另一方面,如果某些函数调用的时间可能是其他函数调用的两倍,则您需要较小的块大小,这样就不会使处理器陷入等待状态。

对于我的问题,每个函数调用应该花费几乎相同的时间(我认为),因此,如果我希望按顺序调用进程,则由于 checkin 开销,我将牺牲效率。

最佳答案

发生这种情况的原因是因为在调用map的开始时,给每个进程预定义的工作量,这取决于chunksize。我们可以通过查看pool.map的来源来得出默认的chunksize

chunksize, extra = divmod(len(iterable), len(self._pool) * 4)
if extra:
  chunksize += 1

因此,对于20个范围和4个进程,我们将得到chunksize为2。

如果我们修改您的代码以反射(reflect)这一点,我们应该得到与您现在得到的结果类似的结果:
proc_pool.map(SomeFunc, range(num_calls), chunksize=2)
这产生输出:
0 2 6 4 1 7 5 3 8 10 12 14 9 13 15 11 16 18 17 19
现在,设置chunksize=1将确保一次仅向池中的每个进程分配一个任务。
proc_pool.map(SomeFunc, range(num_calls), chunksize=1)
与不指定块大小时相比,这应确保合理的数字排序。例如,chunksize为1会产生输出:
0 1 2 3 4 5 6 7 9 10 8 11 13 12 15 14 16 17 19 18

关于python - 特定顺序的multiprocessing pool.map调用函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17903355/

10-08 21:53