Python 并行 Popen

1 投票
2 回答
1311 浏览
提问于 2025-04-17 07:22

我昨晚一直在思考这个问题……

makeflags = ['--prefix=/usr','--libdir=/usr/lib']
rootdir='/tmp/project'
ps = set()

def configModule(m):
    print m
    return Popen(["./autogen.sh"] + makeflags, cwd=rootdir+"/"+m)

for module in ['mod1','mod2','mod3' ... 'mod10']:
    ps.add(configModule(module))

os.wait()

我本以为它会同时启动10个进程,并并行执行./autogen.sh。但是,我观察到前几个configModule似乎在函数被调用后就退出了。我只看到了“print m”这条语句,但没有看到“mod1”中实际执行./autogen.sh的输出。不过,在大约mod4之后,代码开始并行运行。我可以看到CPU的使用率很高,并且不同模块文件夹中也生成了输出。

有没有人知道为什么前几个模块没有产生./autogen.sh的结果?

附注:如果我以串行方式运行这段代码(也就是用subprocess.call而不是Popen),它就能正常工作。

2 个回答

1

一个结构类似的程序,使用了一个虚拟的系统调用,运行得很正常:

from subprocess import *

makeflags = ['--prefix=/usr','--libdir=/usr/lib']
rootdir='/tmp/project'
ps = dict()

def configModule(m):
    print m
    p = Popen("echo start %s; sleep %d; echo finish %s" % (m, 10-m, m), shell=True)
    #p.m = m
    return p

for module in range(10):
    ps[configModule(module)] = module

while ps:
    done = set()
    for p in ps:
        s = p.poll()
        if s is not None:
            print "Module %d: %d" % (ps[p], s)
            done.add(p)
    for p in done:
        del ps[p]
#os.wait()

你确定输出真的缺失了吗,还是说只是延迟了?

顺便说一下:

for module in ('mod%d' % i for i in range(1, 11)):

这样做更优雅...

1

你的代码在我这儿能正常运行,应该可以启动所有的进程。不过你给的信息不太多,我们不知道具体哪里不一样。

在你贴的代码里,没有重定向输出,所以你可能看到的是子进程的 stderr 输出流。不过有一点需要注意:

os.wait()

…这段代码只会等待一个进程。你可能需要使用 Popen 的返回值,然后对每个子进程调用 waitcommunicate。这样你还可以使用返回值来确保它们都正常结束:

# Instead of os.wait():
for p in ps:
    p.wait()
    print 'A process returned:', p.returncode

希望如果一切正常,它们的返回值应该都是 0。

撰写回答