简体   繁体   English

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

[英]Kill children of Python subprocess after subprocess.TimeoutExpired is thrown

I am calling a shell script fom within Python, that spawns multiple child processes.我在 Python 中调用了一个 shell 脚本,它会产生多个子进程。 I want to terminate that process and all of its children, if it did not finish after two minutes.如果两分钟后没有完成,我想终止该进程及其所有子进程。

Is there any way I can do that with subprocess.run or do I have to go back to using Popen?有什么办法可以用 subprocess.run 做到这一点,还是我必须回去使用 Popen? Since run is blocking, I am not able to save the pid somewhere to kill the children in an extra command.由于 run 被阻塞,我无法将 pid 保存在某处以在额外的命令中杀死孩子。 A short code example:一个简短的代码示例:

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

This problem was reported as a bug to the Python developers.此问题已作为错误报告给 Python 开发人员。 It seems to happen specifically when stderr or stdout is redirected.当 stderr 或 stdout 被重定向时,它似乎特别发生。 Here is a more correct version of @Tanu's code.这是@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 doesn't accept timeout as a parameter. Popen 不接受timeout作为参数。 It must be passed to communicate .必须通过它才能进行communicate On Posix OSs, terminate is more gentle than kill , in that it reduces the risk of creating zombie processes.在 Posix 操作系统上, terminatekill更温和,因为它降低了创建僵尸进程的风险。

Quoting from the docs:引用文档:

subprocess.run - This does not capture stdout or stderr by default. subprocess.run - 默认情况下不会捕获 stdout 或 stderr。 To do so, pass PIPE for the stdout and/or stderr arguments.为此,请为 stdout 和/或 stderr 参数传递 PIPE。

Don't have to use Popen() if you don't want to.如果您不想,不必使用 Popen()。 The other functions in the module, such as .call(), .Popen().模块中的其他函数,例如 .call()、.Popen()。

There are three 'file' streams: stdin for input, and stdout and stderr for output.有三个“文件”流:用于输入的 stdin,以及用于输出的 stdout 和 stderr。 The application decides what to write where;应用程序决定在哪里写什么; usually error and diagnostic information to stderr, the rest to stdout.通常错误和诊断信息到 stderr,其余到 stdout。 To capture the output for either of these outputs, specify the subprocess.PIPE argument so that the 'stream' is redirected into your program.要捕获这些输出中的任何一个的输出,请指定 subprocess.PIPE 参数,以便将“流”重定向到您的程序中。

To kill the child process after timeout:超时后终止子进程:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM