【问题标题】:Why does python keep buffering stdout even when flushing and using -u?为什么即使在刷新和使用 -u 时,python 也会继续缓冲标准输出?
【发布时间】:2011-12-19 21:45:45
【问题描述】:
$ cat script.py
import sys

for line in sys.stdin:
    sys.stdout.write(line)
    sys.stdout.flush()

$ cat script.py - | python -u script.py

输出是正确的,但只有在我按下 Ctrl-D 后才会开始打印,而以下内容会立即开始打印:

$ cat script.py - | cat

这让我认为缓冲不是来自猫。

我设法让它工作:

for line in iter(sys.stdin.readline, ""):

正如这里所解释的:Streaming pipes in Python,但我不明白为什么以前的解决方案不能按预期工作。

【问题讨论】:

    标签: python stdout pipe buffering


    【解决方案1】:

    Python 手册页揭示了您问题的答案:

       -u     Force stdin, stdout and stderr to be totally unbuffered.  On systems where it matters, also put stdin, stdout and stderr in binary mode.  Note that
              there  is  internal  buffering  in  xreadlines(),  readlines()  and file-object iterators ("for line in sys.stdin") which is not influenced by this
              option.  To work around this, you will want to use "sys.stdin.readline()" inside a "while 1:" loop.
    

    也就是说:文件对象迭代器的内部缓冲是罪魁祸首(并且它不会随着 -u 而消失)。

    【讨论】:

      【解决方案2】:

      如果输出到管道,cat 默认会阻塞缓冲。因此,当您在 cat 命令中包含 - (stdin) 时,它会在输出任何内容之前等待获取 EOF(您的 ctrl-D 关闭标准输入流)或 8K(可能)数据。

      如果将 cat 命令更改为“cat script.py |”您会看到它按预期工作。

      另外,如果你在 script.py 的末尾添加 8K 的 cmets,它也会立即打印出来。

      编辑:

      以上是错误的。 :-)

      原来 file.next()(由文件迭代器使用,即用于文件中的行)有一个隐藏的预读缓冲区,readline() 不使用它,它只是读取一个字符,直到它看到一个换行符或 EOF。

      【讨论】:

      • 我编辑了我的问题,解释了为什么它似乎不是来自猫本身。
      • 您的更改没有任何区别......这是第一只正在缓冲的猫,因为输出将进入管道。在管道之后更换水槽不会改变任何东西。您可以通过简单地执行“cat script.py -”并看到它立即输出 script.py 来看到这一点,因为它会进入终端而不是管道。
      • 也许我的例子不清楚,但我认为它表明第一只猫没有缓冲,因为 script.py 的内容在 EOF 发送到第一只猫之前出现。
      • 就像我说的,将 8K 的 cmets 添加到 script.py 中,您会看到它的工作原理。
      • 我知道 cat 可能会缓冲它的输出,但我表明在这种情况下它不会(例如cat script.py - | cat)。您的回答与我的问题无关。
      猜你喜欢
      • 1970-01-01
      • 2016-10-25
      • 2013-07-02
      • 2022-01-11
      • 1970-01-01
      • 2022-10-02
      • 1970-01-01
      • 2019-11-22
      • 2021-05-03
      相关资源
      最近更新 更多