【问题标题】:run subprocesses in parallel并行运行子进程
【发布时间】:2014-07-12 04:25:10
【问题描述】:

我有一个 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

所以我基本上想在将其输出捕获到文件时以并行方式运行此命令。完成所有实例后,我想继续脚本

【问题讨论】:

标签: python subprocess


【解决方案1】:

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

附:您是否查看过subprocess module 上的 Python 文档?

【讨论】:

  • 如果在 for 循环开始调用communicate() 之前,它们的 stdout/stderr 管道已填满,您将面临后续进程将停止的风险。一种简单的解决方案是将 stdout/err 通过管道传输到临时文件。
  • 我可以直接将 stdout 和 stderror 链接到文件句柄吗?标准输出=文件句柄?也不应该出来吧,err = cp.communicate()?
  • 它们确实可以设置为现有的文件句柄。
  • 如果我将它们直接路由到文本文件,我将如何等待进程完成?
  • @prgmjunkie,是的。 stdout=open('my-process-out.txt', 'w') 工作。
【解决方案2】:

我喜欢在这种情况下使用GNU Parallel (http://www.gnu.org/software/parallel/)(需要 *nix),因为它提供了一种快速获得并行性的方法并且有很多选项,包括在最后重新组织输出,这样它全部从每个进程按顺序流到一起,但不是交错的。您还可以指定一次要运行的编号,可以是特定编号,也可以与您拥有的核心数相匹配,它会将其余命令排队。

只需使用subprocess.check_outputshell=True 使用您的命令字符串调用parallel。如果您有一个要插值的变量,例如您要对其运行命令的SQL 表的列表,则parallel 也擅长处理该问题——您可以使用管道输入文本文件的内容论据。

如果命令完全不同(而不是同一命令的变体),请将完整的命令放在您通过管道传递到 parallel 的文本文件中。

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

【讨论】:

  • shell=True 几乎在任何上下文中都是不安全的。
  • potential issues,但肯定有没有问题的情况。例如输入不是来自外部网络等的任意来源。
猜你喜欢
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 2017-05-31
  • 2013-05-03
  • 2011-12-16
  • 1970-01-01
  • 2021-10-10
  • 2022-01-25
相关资源
最近更新 更多