Linux和Windows上缓冲stdout的区别

时间:2017-08-07 11:26:18

标签: python linux windows stdout

写入控制台时,在Windows和Linux上缓存stdout的方式似乎有所不同。考虑一下这个小的python脚本:

import time
for i in xrange(10):
    time.sleep(1)
    print "Working" ,

在Windows上运行此脚本时,我们看到Working一个接一个地出现,中间有第二个等待。在Linux上,我们必须等待10秒,然后立即出现整行。

如果我们将最后一行更改为print "Working",则每行都会单独出现在Linux上。

所以在Linux上,stdout似乎是行缓冲的,而在Windows上根本没有。我们可以使用-u - 选项关闭缓冲(在这种情况下,Linux上的脚本与Windows上的脚本具有相同的行为)。 documentation说:

  

-u强制stdin,stdout和stderr完全无缓冲。

实际上,它并没有说,没有-u - 选项stdinstdout都会被缓冲。因此我的问题是:

  1. 在Linux / Windows上出现不同行为的原因是什么?
  2. 是否有某种保证,如果重定向到文件stdout将被缓冲,无论哪个操作系统?至少在Windows和Linux中就是这种情况。
  3. 我主要担心的是(正如一些答案所假设的)刷新信息时,但是如果stdout没有被缓冲,那么它可能是一个严重的性能损失而且不应该依赖它。

    编辑:值得注意的是,对于Python3,Linux和Windows的行为是相同的(但这并不奇怪,因为行为是由{{1的参数显式配置的}} - 方法)

4 个答案:

答案 0 :(得分:4)

行为不同,因为缓冲通常是未指定,这意味着实现可以做任何他们想做的事情。并且,这意味着实现可以随时更改,或者以未记录的方式更改,甚至可能在同一平台上。

例如,如果你在Linux上打印一个“足够长”的字符串,没有换行符(\n),它可能会被写入,好像它有一个换行符(因为它超过了缓冲区)。您还可能会发现缓冲区大小因stdout,管道和文件而异。

非常糟糕依赖于未指定的行为,因此在您真正需要写入字节时请使用flush()

如果你需要控制缓冲(例如出于性能原因),那么你需要在write()flush()之上实现自己的缓冲。这样做非常简单,这使您可以完全控制实际写入字节的方式和时间。

答案 1 :(得分:4)

假设您正在谈论CPython(可能),这与底层C实现的行为有关。

ISO C标准提到(C11 7.21.3 Files /3)三种模式:

  • 无缓冲(字符尽快出现);
  • 完全缓冲(当缓冲区已满时出现字符);和
  • 行缓冲(字符出现在换行符输出中)。

其他触发器导致字符出现(例如缓冲区即使没有输出换行符填满,在某些情况下请求输入,或关闭流)但它们并不重要在你的问题的背景下。

重要的是同一标准中的7.21.3 Files /7

  

最初打开时,标准错误流未完全缓冲;当且仅当可以确定流不参考交互设备时,标准输入和标准输出流是完全缓冲的。

请注意那里的摆动室。标准输出可以是行缓冲或无缓冲,除非实现确定它不是交互设备。

在这种情况下(控制台),它一个交互设备,因此不允许实现使用unbuffered。然而,允许选择其他两种模式中的任何一种,这就是为什么你会看到差异。

无缓冲输出会在您输出消息后立即显示消息(Windows行为)。行缓冲将延迟直到输出换行符(您的Linux行为)。

如果你真的想确保无论模式如何刷新你的消息,只需自己冲洗它们:

import time, sys
for i in xrange(10):
    time.sleep(1)
    print "Working",
    sys.stdout.flush()
print

在保证在重定向到文件时缓冲输出方面,这将在我已经展示的标准中引用。如果可以确定流使用非交互设备,则将完全缓冲该流。这不是绝对保证,因为它没有说明如何确定,但如果任何实施无法解决这个问题,我会感到惊讶。

在任何情况下,您都可以通过重定向输出并监视文件来测试特定的实现,以查看每个输出或最后是否刷新一次。

答案 2 :(得分:1)

其他地方已有答案,但我将在下面进行总结。

  1. Windows与Linux的不同行为的原因是由于打印命令的实现方式(如eryksun的评论中所述)。您可以通过herehere

  2. 获取有关该信息的更多信息
  3. 这可以在python中以多种方式解决。有关here的更多内容。

答案 3 :(得分:1)

此问题自2011年起就已知,请参阅此Python bug issue #11633

打印功能不进行任何缓冲。它写入的文件对象可能。即使sys.stdout可能会也可能不会。

考虑到行为的差异,找到的解决方案是更新文档,以便以粗体包含以下句子:

  

file参数必须是带有write(string)方法的对象;如果它   不存在或无,将使用sys.stdout。 输出缓冲是   由文件确定。

值得注意的是:

  

Guido说它应该做的事情是“需要刷新的应用程序应该调用flush()。”因此,代码更改被拒绝。