在并行中运行子进程

7
我有一个Python脚本,需要调用某个应用程序3次。这些调用应该是并行的,因为它们需要数小时才能完成,并且彼此之间没有依赖关系。但是,脚本应该在所有调用都完成后停止,并进行一些清理工作。
以下是一些代码:
#do some stuff

for work in worklist:   # these should run in parralel
    output=open('test.txt','w')
    subprocess.call(work,stdout=output,stderr=output)
    output.close()

# wait for subprocesses to finish

# cleanup

我希望同时运行此命令并将其输出捕获到文件中。一旦所有实例完成,我想继续执行脚本。


2个回答

11

subprocess.call()是阻塞的。这意味着每个调用都必须在继续之前等待子进程完成。

你需要的是将参数传递给subprocess.Popen构造函数中,这样你的子进程将会启动而不会阻塞。

稍后,你可以通过调用Popen.communicate()Popen.wait()来将这些子进程合并在一起。

child_processes = []
for work, filename in worklist:
    with io.open(filename, mode='wb') as out:
        p = subprocess.Popen(work, stdout=out, stderr=out)
        child_processes.append(p)    # start this one, and immediately return to start another

# now you can join them together
for cp in child_processes:
    cp.wait()                         # this will block on each child process until it exits

P.S. 你有查看过Python的subprocess模块文档吗?


2
我喜欢在这种情况下使用 GNU Parallelhttp://www.gnu.org/software/parallel/)(需要*nix),因为它提供了一种快速获取并行性的方法,并且有许多选项,包括重新组织输出,使其按顺序但不交错地从每个进程流到一起。你还可以指定你想要同时运行的数量,可以是一个特定的数字,也可以与你拥有的核心数匹配,它会排队执行其余的命令。

只需使用带有 shell=Truesubprocess.check_output 调用你的命令字符串即可调用 parallel 。如果你有一个要插入的变量,比如你想对一组SQL表运行你的命令,parallel 处理起来也很好 —— 你可以将文本文件的内容作为参数输入。

如果这些命令完全不同(而不是同一命令的变体),则将完整的命令放入要传递给 parallel 的文本文件中。

你也不需要做任何特殊的事情来等待它们完成,因为check_output调用会阻塞直到parallel命令完成。

shell=True 在几乎任何情况下都是不安全的。 - jbarlow
1
存在潜在问题,但在某些情况下是可以接受的。例如,输入不是来自外部网络的任意来源等。 - khampson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接