简体   繁体   English

Python 进程终止后通信被阻止

[英]Python communicate is blocked after process kill

I'm running a Python script that executes a Bash subprocess.我正在运行执行 Bash 子进程的 Python 脚本。 If the Bash subprocess times out, then the Python script is expected to print the stdout of the Bash subprocess.如果 Bash 子进程超时,则 Python 脚本预计会打印 Bash 子进程的标准输出。 The Python script works as expected, however, if the Bash subprocess is executed using the "sudo" keyword, then reading the stddout after the timeout blocks the Python. Python 脚本按预期工作,但是,如果使用“sudo”关键字执行 Bash 子进程,则在超时后读取 stddout 会阻塞 ZA7F5F35426B927411FC9231B563821。

The Bash script (named test-bash.sh) looks like that: Bash 脚本(名为 test-bash.sh)如下所示:

#!/bin/sh
while :
do
        echo "Press [CTRL+C] to stop.."
        sleep 1
done

The Python script looks like that: Python 脚本如下所示:

import subprocess
proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)
try:
    outs, errs = proc.communicate(timeout=3)
except subprocess.TimeoutExpired:
    proc.kill()
    print("Succesfully killed")
    outs, errs = proc.communicate()
    print("Stdout: {}".format(outs))

The last print is never called, being blocked on communicate(), unless we remove the "sudo" from:最后一次打印永远不会被调用,在通信()上被阻止,除非我们从以下位置删除“sudo”:

proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)

What is the reason for the blocking of communicate()?阻塞通信()的原因是什么? How do I unblock it and read stddout() if I must run the Bash subprocess using "sudo"?如果我必须使用“sudo”运行 Bash 子进程,我该如何解锁它并读取 stddout()?

The problem can be reproduced even without sudo provided that shell=True .即使没有sudo也可以重现问题,前提是shell=True It's just like John Bollinger explained above, so I'll spare us the reciting.就像上面解释的约翰·布林格一样,所以我将省去我们的背诵。 Fortunately Popen provides a means to deal with such multi-level subprocesses - it allows to start a new session and therewith to create a process group by which all subprocesses can be killed.幸运的是, Popen提供了一种处理这种多级子进程的方法——它允许启动一个新的 session 并创建一个进程组,通过该进程组可以杀死所有子进程。

# add start_new_session=True argument
proc = subprocess.Popen(…, stdout=subprocess.PIPE, start_new_session=True)
…
# replace proc.kill() by
    import os
    import signal
    os.killpg(proc.pid, signal.SIGTERM)

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

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