从线程中的子进程标准输出读取时的随机行为
Random behaviour while reading from subprocess stdout in a thread
我正在编写一个脚本来启动一个进程并检查其标准输出(在 运行 期间,而不是在执行结束时)。
明显的选择似乎有一个线程将被阻止从进程 stdout 读取行。
我已经使用 WSL2 bash 测试了它:
python __main__.py 'echo ok'
结果是随机的,导致以下情况之一:
- 执行终止,没有任何输出
- "ok" 按预期打印
- “ok”后跟一个 'ValueError: readline of closed file' 异常
知道问题出在哪里吗?
代码:
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()
.
来实现
我正在编写一个脚本来启动一个进程并检查其标准输出(在 运行 期间,而不是在执行结束时)。
明显的选择似乎有一个线程将被阻止从进程 stdout 读取行。
我已经使用 WSL2 bash 测试了它:
python __main__.py 'echo ok'
结果是随机的,导致以下情况之一:
- 执行终止,没有任何输出
- "ok" 按预期打印
- “ok”后跟一个 'ValueError: readline of closed file' 异常
知道问题出在哪里吗?
代码:
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()
.