关闭缓冲

12 投票
4 回答
10444 浏览
提问于 2025-04-17 07:53

在下面这个问题中,问的是缓冲区在哪里,以及如何关闭它。

我在一个Python程序中这样输出到标准输出(stdout):

for line in sys.stdin:
    print line

这里面有一些缓冲的情况:

tail -f data.txt | grep -e APL | python -u Interpret.py

我尝试了以下方法来解决可能的缓冲问题,但都没有成功:

  • 像上面那样,在调用Python时加上 -u 参数
  • 在每次调用 sys.stdout.write() 后,调用 sys.stdout.flush() ... 这些方法都导致Python创建了一个缓冲流,等了大约一分钟才打印出前几行。
  • 使用了以下修改过的命令:

    stdbuf -o0 tail -f data.txt | stdbuf -o0 -i0 grep -e APL | stdbuf -i0 -o0 python -u Interpret.py

为了验证我的预期,我尝试了:

tail -f data.txt | grep -e APL 

这个命令产生了稳定的输出流 ... 显然没有Python命令那么缓冲。

那么,我该如何关闭缓冲呢?答案是:原来在管道的两端都有缓冲。

4 个回答

3

你遇到的问题出在你的for循环上。它会在继续执行之前等待文件结束符(EOF)。你可以用下面的代码来解决这个问题。

while True:
    try:
        line = sys.stdin.readline()
    except KeyboardInterrupt:
        break 

    if not line:
        break

    print line,

试试看这个方法。

12

file.readlines()for line in file 这两种方法都有内部缓存,这种缓存不会受到 -u 选项的影响(可以查看 -u 选项说明)。建议使用

while True:
   l=sys.stdin.readline()
   sys.stdout.write(l)

来替代。

顺便提一下,如果 sys.stdout 指向终端,它默认是行缓冲的,而 sys.stderr 是没有缓冲的(可以查看 标准输入输出缓冲)。

6

我认为问题出在 grep 的输出缓冲上。当你使用管道命令 tail -f | grep ... | some_other_prog 时,它会这样做。为了让 grep 每行都立即输出,可以使用 --line-buffered 这个选项:

% tail -f data.txt | grep -e APL --line-buffered | test.py
APL

APL

APL

这里的 test.py 是:

import sys
for line in sys.stdin:
    print(line)

(在 Linux 和 gnome-terminal 上测试过。)

撰写回答