【发布时间】:2014-02-01 07:12:47
【问题描述】:
我需要通过多处理运行一系列独立的子进程调用。我提前知道,其中一些工作的运行速度会比其他工作慢几个数量级。为了有效利用处理器时间,我认为首先将慢速作业排队是有意义的。这样,我希望避免奇怪的情况,即最后一个长时间运行的作业被安排并且剩余的处理器处于空闲状态。在这种特殊情况下,实际结果是否按顺序产生并不重要(因为各个进程创建的文件仅在所有进程完成后才使用)。重要的是,慢速作业首先/优先安排。我的第一个问题是,我该如何实现?
即使在阅读了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 的块大小来解决,但我不明白为什么(有人可以解释一下吗?)。我的最后一个问题是:这是否意味着我应该使用map_async(chunksize=1) 进行设置?
谢谢, 安德烈亚斯
PS:我正在使用 Python 2.7,以防万一。
【问题讨论】:
-
能否请您阅读此stackoverflow.com/questions/17903355/…,您将对块大小有所了解
-
谢谢。这解释了示例代码的行为。
-
块大小已经解释过了,现在有什么问题?
-
如果您想要按顺序排列,为什么要使用
multiprocessing?如果您只想进行一些连续的计算,那么您不能依赖时间。如果您想要任何类型的同步,您必须使用一些synchronization primitive,例如Barrier。 -
嗨 Janne,在阅读了 yopy 提供的 chunksize 链接后,我明白现在发生了什么,现在可以回答我所有的问题。如果 yopy 将其添加为答案而不是评论,我会将其标记为正确。