从线程中的子进程标准输出读取时的随机行为

Random behaviour while reading from subprocess stdout in a thread

我正在编写一个脚本来启动一个进程并检查其标准输出(在 运行 期间,而不是在执行结束时)。

明显的选择似乎有一个线程将被阻止从进程 stdout 读取行。

我已经使用 WSL2 bash 测试了它:

python __main__.py 'echo ok'

结果是随机的,导致以下情况之一:

知道问题出在哪里吗?

代码:

import argparse
from subprocess import Popen, PIPE
import sys
import threading


class ReadlineThread(threading.Thread):

    def __init__(self, proc):
        threading.Thread.__init__(self)
        self._proc = proc

    def run(self):
        while self._proc.poll() is None:
            line = self._proc.stdout.readline()
            sys.stdout.buffer.write(line)
            sys.stdout.flush()


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('command', nargs='+', help='bar help')
    args = parser.parse_args()

    with Popen(args.command, stdout=PIPE, stderr=PIPE, shell=True) as proc:
        stdout_thread = ReadlineThread(proc)
        stdout_thread.start()


if __name__ == "__main__":
    main()

创建线程时,它会成为父进程的一部分。父进程是运行主函数的线程。在您的主函数中,您调用 stdout_thread.start(),它开始启动线程的过程,然后立即 returns。在那之后,您的主函数中没有更多代码,这导致 python 关闭主进程。由于您的线程是主进程的一部分,因此当主进程终止时它将被关闭。同时,您启动的线程仍在创建中。

这里有所谓的竞争条件。您的线程正在启​​动,同时它所属的进程正在关闭。如果您的线程设法在进程终止之前启动并完成其工作,您就会得到预期的结果。如果进程在线程启动之前终止,则不会得到任何输出。第三种情况,进程在线程读完它之前就关闭了它的stdout,导致错误。

要解决此问题,您应该在主函数中等待生成的线程完成,这可以通过调用 stdout_thread.join().

来实现