我有一个python子进程,我正在尝试从中读取输出和错误流。目前,我可以使用它,但是只能从stderr中读取后,才能从stdout中读取。看起来是这样的:

process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_iterator = iter(process.stdout.readline, b"")
stderr_iterator = iter(process.stderr.readline, b"")

for line in stdout_iterator:
    # Do stuff with line
    print line

for line in stderr_iterator:
    # Do stuff with line
    print line

如您所见,stderr for循环在stdout循环完成之前无法启动。我如何修改它以便能够以正确的顺序从行中读取两者?

需要说明的是:我仍然需要能够区分一行是stdout还是stderr,因为它们在我的代码中将被区别对待。

最佳答案

这是一种基于selectors的解决方案,但该解决方案保留顺序并流变长字符(甚至是单个字符)。

诀窍是使用 read1() 而不是read()

import selectors
import subprocess
import sys

p = subprocess.Popen(
    ["python", "random_out.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

sel = selectors.DefaultSelector()
sel.register(p.stdout, selectors.EVENT_READ)
sel.register(p.stderr, selectors.EVENT_READ)

while True:
    for key, _ in sel.select():
        data = key.fileobj.read1().decode()
        if not data:
            exit()
        if key.fileobj is p.stdout:
            print(data, end="")
        else:
            print(data, end="", file=sys.stderr)

如果您需要测试程序,请使用它。
import sys
from time import sleep


for i in range(10):
    print(f" x{i} ", file=sys.stderr, end="")
    sleep(0.1)
    print(f" y{i} ", end="")
    sleep(0.1)

07-26 09:30