Python subprocess.Popen 投票似乎挂起但沟通有效

Python subprocess.Popen poll seems to hang but communicate works

child = subprocess.Popen(command,
                        shell=True,
                        env=environment,
                        close_fds=True,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
                        stdin=sys.stdin,
                        preexec_fn=os.setsid
                       )

child_interrupted = False
while child.poll() is None:
    if Signal.isInterrupted():
        child_interrupted = True
        os.killpg(os.getpgid(child.pid), signal.SIGTERM)
        break
    time.sleep(0.1)

subout = child.communicate()[0]
logging.info(subout)

以上适用于它执行的大多数命令 (90%) 但对于某些命令它会挂起

对于那些反复挂起的命令,如果我去掉下面的命令,它就可以正常工作:

    child_interrupted = False
    while child.poll() is None:
        if Signal.isInterrupted():
            child_interrupted = True
            os.killpg(os.getpgid(child.pid), signal.SIGTERM)
            break
        time.sleep(0.1)

我假设那些挂起的命令,child.poll() is None 即使工作完成了??

communicate() 可以告诉进程已完成但 poll() 不能?

我已经在这些进程上执行了 ps -ef
并且它们仅在 child.poll() 代码到位时才失效
知道为什么吗?

看起来像 defunct 意味着 "That's a zombie process, it's finished but the parent hasn't wait()ed for it yet." 好吧,我正在轮询,看看我是否可以打电话给 wait/communitcate...

您已将 Popen 对象设置为通过管道接收子进程的 stdout。问题是,在进程退出之前,您不会从该管道读取数据。如果该过程产生足够的输出来填充 OS 级别的管道缓冲区,并且您没有排空管道,那么您就会陷入僵局;子进程希望您读取其写入的输出,以便它可以继续写入,然后退出,而您正在等待它退出,然后再读取输出。

如果需要进行显式轮询和中断检查,解决此死锁的最简单方法可能是启动一个排空管道的线程:

... launch the thread just after Popen called ...

draineddata = []
# Trivial thread just reads lines from stdout into the list
drainerthread = threading.Thread(target=draineddata.extend, args=(child.stdout,))
drainerthread.daemon = True
drainerthread.start()

... then where you had been doing communicate, change it to: ...
child.wait()
drainerthread.join()
subout = b''.join(draineddata)  # Combine the data read back to a single output