Popen.communicate 卡住,直到子进程生成的进程终止

Popen.communicate is stuck until process spawned by sub-process terminates

我有以下三个脚本,当我 运行 main.py 文件时,它生成 child.py 再次执行 subchild.py 并迅速终止,subchild.py 但是一直执行很长时间。

问题在于,main.py 在 p.communicate() 处被阻塞,直到 subchild.py 终止。如果我打开任务管理器并立即杀死 运行ning subchild.py main.py returns child.py

的输出

所以我的问题如下

    # main.py file

    if __name__ == '__main__':
        import subprocess
        p = subprocess.Popen(
            ["python", "child.py"],
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        out, _ = p.communicate()
        print(out)


    # child.py file

    if __name__ == '__main__':
        import subprocess
        print("Child running")
        p = subprocess.Popen(["python", "subchild.py"])
        print("Child pid - ", p.pid)
        exit(1)


    # subchild.py file

    if __name__ == '__main__':
        import time
        time.sleep(10000)

注意:我正在 Windows 7 Enterprise 上尝试此操作。我正在使用 python3.6.6

评论后更新: 在 main.py 上,我需要 child.py 的 pid、stdout、stderr 和进程对象,以便我可以在以后的任何时候从 main.py 中删除 child.py。这段代码是一个小片段,是我正在构建的一些 API 的一部分,用户希望控件在他愿意的情况下终止进程。 subprocesses.call 或 subprocesses.run 不会让我控制 process 对象。我也无法控制我将收到什么 child.py 命令作为 main.py 的输入,所以我需要以某种方式不等待 subchild.py 并立即退出 child.py 完成后立即输出。

现在,child.py 将始终等待子child.py 完成。如果您不需要等待,可以尝试 subprocess.call() 作为 child.py 代码中的替代方法。将 Popen() 逻辑替换为 call() 逻辑。

p = subprocess.call(["python", "subchild.py"])

这里有一个参考:https://docs.python.org/2/library/subprocess.html#subprocess.call


另一种方法是保留代码,因为它实际上是对 main.py 文件中使用 .call() 的更改。

import subprocess
p = subprocess.call(
    ["python", "child.py"],
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE,
    stderr=subprocess.PIPE
)

您提到您不能使用 .call() 因为您需要终止它,但事实并非如此。进行此更改应该允许您:

  • return main.py 和 child.py 很快,
  • 它将打印来自 child.py 和
  • 的子进程的 ID
  • subchild.py 会继续运行

您的 communicate 调用不只是等待 child 完成。它首先尝试读取 child 的标准输出和标准错误的全部内容。

即使 child 完成了,parent 也无法停止阅读,因为 grandchild 继承了 child 的标准输入、标准输出和标准错误。 parent 需要等待 grandchild 完成,或者至少等待 grandchild 关闭其标准输出和标准错误,然后 parent 才能确定它已完成正在阅读。

最后我自己找到了解决方案,这似乎是 python 的一个悬而未决的问题。很高兴看到这个修复。 https://bugs.python.org/issue26731