Python在保留顺序的同时分别从子进程stdout和stderr中读取
问题内容:
我有一个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)