Python 的 select() 延迟报告子进程输出的存在

Python's select() delays reporting presence of output from subprocesses

我是 运行 这个简单的 Python 程序,用于合并来自两个子进程的输出行:

import select
from subprocess import PIPE, Popen
import sys

subprocs = [
    Popen(cmdline, stdout=PIPE) for cmdline in
    [['./repeat', 'abc'], ['./repeat', 'xyz']]
]
while True:
    rstreams, _, _ = select.select([p.stdout for p in subprocs], [], [])
    for stream in rstreams:
        sys.stdout.buffer.write(stream.readline())

… 其中 repeat 是一个简单的脚本,它会定期生成输出:

#!/bin/bash
while sleep 1 ; do echo $@ ; done

我希望将两个子流程的输出按行合并,以便合并后的输出以任意顺序包含 abcxyz 行,并及时转发. (不希望混合数据,例如 abxyzc。)

但是,我发现上面的 Python 程序很长时间没有输出,或者直到我按下 CtrlC.

(我已经尝试将 stream.readline() 更改为 stream.read(1),以防 readline() 挂起时出现问题,尽管我不想要那种交错,但它没有帮助。发生在 Python 3.5.2 on Linux 和 Python 3.7.6 on macOS.)

为什么 select() 等待,而子进程显然正在生成输出?

根本原因是您使用了sys.stdout.buffer,它内部有一个缓冲区,因此我们无法立即看到结果。

我们可以在写入后显式刷新结果。将 sys.stdout.buffer.flush() 放在 buffer.write() 之后。或者只使用 print(stream.readline()) 而不是 sys.stdout.buffer.