在subprocess.TimeoutExpired被抛出后,杀死Python子进程的子进程

时间:2017-07-04 15:23:19

标签: python python-3.x subprocess

我在Python中调用一个shell脚本,它会生成多个子进程。如果两分钟后没有完成,我想终止该过程及其所有孩子。

有什么方法可以用subprocess.run做到这一点,还是我必须回到使用Popen?由于运行阻塞,我无法在某个地方保存pid以在额外命令中杀死子进程。一个简短的代码示例:

try:
    subprocess.run(["my_shell_script"], stderr=subprocess.STDOUT, timeout=120)
except subprocess.TimeoutExpired:                                                                      
    print("Timeout during execution")

2 个答案:

答案 0 :(得分:1)

此问题已向Python开发人员报告为bug。当stderr或stdout重定向时,这似乎特别发生。 这是@Tanu代码的更正确版本。

import subprocess as sp

try:
    proc = sp.Popen(['ls', '-l'], stdout=sp.PIPE, stderr=sp.PIPE)
    outs, errs = proc.communicate(timeout=120)
except sp.TimeoutExpired:
    proc.terminate()

Popen不接受timeout作为参数。必须将其传递到communicate。 在Posix操作系统上,terminatekill更柔和,因为它降低了创建僵尸进程的风险。

答案 1 :(得分:0)

引用文档:

  

subprocess.run - 默认情况下,它不捕获stdout或stderr。为此,请为stdout和/或stderr参数传递PIPE。

如果你不想,不必使用Popen()。模块中的其他函数,例如.call(),. Popen()。

有三个'文件'流:输入的stdin,输出的stdout和stderr。应用程序决定在哪里写;通常是stderr的错误和诊断信息,其余的是stdout。要捕获这些输出中的任何一个的输出,请指定subprocess.PIPE参数,以便将“stream”重定向到您的程序中。

超时后终止子进程:

import os
import signal
import subprocess

try:
    proc = subprocess.Popen(["ls", "-l"], stdout=PIPE, stderr=PIPE, timeout=120)
except subprocess.TimeoutExpired:
    os.kill(proc.pid, signal.SIGTERM)