我需要通过多处理运行一系列独立的子进程调用。我事先知道,其中一些工作的执行速度比其他工作慢。为了有效利用处理器时间,我认为首先将慢速作业排队是有意义的。这样我希望避免奇怪的情况,其中一个长时间运行的作业最后被安排,剩下的处理器空闲。在这种特殊情况下,实际结果是否按顺序产生并不重要(因为各个进程创建的文件仅在所有进程完成后才使用)。但重要的是,慢速工作首先/优先安排。我的第一个问题是,我该如何做到这一点?
即使在阅读multiprocessing documentation和this excellent post explaining the differences between map(), map_async() etc.后,我仍然有点困惑。因此,我的第二个问题是:在这种情况下,我应该使用Pool.map()
而不是Pool.map_async()
,还是其他什么?
我尝试了map()
和map_async()
,但起初我没有观察到任何一种预期的行为。以下示例运行进程,除了创建文件和休眠之外没有太多工作。
import subprocess
import multiprocessing
import time
import os
import glob
import sys
NUM_PROCS = 2
def work(cmd):
return subprocess.call(cmd, shell=True)
def generate_cmds(n=10):
for i in xrange(n):
yield "sleep 2 && touch %d.log" % (i)
def main():
assert len(sys.argv)==2, ("missing arg: async=[0|1]")
async = sys.argv[1]=='1'
results = []
pool = multiprocessing.Pool(processes=NUM_PROCS)
if async:
print "map_async()"
p = pool.map_async(work, generate_cmds(), callback=results.extend)
p.wait()# or p.close() and p.join()
else:
print "map()"
results = pool.map(work, generate_cmds())
print "results: %s" % (results)
for f in glob.glob("[0-9]*.log"):
print f, time.strftime('%H:%M:%S',
time.localtime(os.path.getmtime(f)))
if __name__ == "__main__":
main()
我假设创建文件的时间戳应与map()
的命令顺序匹配,因为所有进程大致需要相同的时间才能完成,但它们没有(如果我不玩) CHUNKSIZE)。似乎所有其他命令同时运行:
$ python subp.py 0
map()
results: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0.log 14:36:57
1.log 14:36:59
2.log 14:36:57
3.log 14:36:59
4.log 14:37:01
5.log 14:37:03
6.log 14:37:01
7.log 14:37:03
8.log 14:37:05
9.log 14:37:07
我知道这可以通过使用1的chunksize来修复,但我不明白为什么(有人可以解释吗?)。我的最后一个问题是:这是否意味着我应该使用map_async(chunksize=1)
作为我的设置?
谢谢, 安德烈亚斯
PS:我正在使用Python 2.7以防万一。
答案 0 :(得分:0)
回答我自己的问题:
在我的情况下,无论我使用map()还是map_async()都没关系,因为结果的顺序并不重要。然而,排队顺序/执行顺序是如此,因此将chunksize设置为1非常重要(提供的链接yopy给了我最后的线索)。每个处理器将运行chunksize迭代,并自动确定chunksize。这可能会产生不必要的副作用,即慢速作业(排队第一)被分配给一个(或少数)处理器,而不是在几个处理器之间平均分配。
安德烈亚斯