在Linux和Windows上stdout的缓冲差异

写入控制台时,在Windows和Linux上如何缓冲stdout似乎有所不同。 考虑这个小python脚本:

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

在Windows上运行这个脚本时,我们看到Working s正在一个接一个地出现在第二个等待的中间。 在Linux上,我们必须等待10秒钟,然后整个一行出现。

如果我们将最后一行改为print "Working" ,则每行也会在Linux上单独显示。

所以在Linux上, stdout似乎是行缓冲的,在Windows上根本就没有。 我们可以使用-uclosures缓冲(在这种情况下,Linux上的脚本与Windows上的脚本具有相同的行为)。 该文件说:

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

所以实际上,并没有说没有-u stdinstdout被caching了。 因此我的问题是:

  1. Linux / Windows上不同行为的原因是什么?
  2. 有没有某种保证,如果redirect到一个文件stdout将被缓冲,不pipe是哪个操作系统? 至less对于Windows和Linux来说,情况似乎如此。

我的主要担心是(如某些答案所假设的) 信息被刷新,但是如果stdout没有被缓冲,那么可能是一个严重的性能问题,不应该依赖它。

编辑:值得注意的是,对于Python3而言,对于Linux和Windows来说,行为是相同的(但是这并不令人惊讶,因为行为是由print -method的参数明确configuration的)。

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

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

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

还有其他触发器会导致出现字符(例如,即使没有输出换行符,在某些情况下请求输入,或者关闭数据流,缓冲区也会被填满),但是在问题的上下文中它们并不重要。

7.21.3 Files /7在同样的标准中重要的:

最初打开时,标准错误流没有被完全缓冲; 标准输入和标准输出流是完全缓冲的,当且仅当流可以被确定为不涉及交互设备时。

注意那里的摆动室。 标准输出既可以是线路缓冲的,也可以是无缓冲的,除非实现知道它确实不是交互式设备。

在这种情况下(控制台),它一个交互式设备,所以不允许使用无缓冲的实现。 这允许选择其他两种模式之一,这就是为什么你看到不同之处。

无缓冲的输出会在你输出它们(你的Windows行为)时立即看到消息。 行缓存会延迟,直到输出换行符(您的Linux行为)。

如果你真的想确保你的消息被刷新而不管模式如何,只需要自己刷新它们:

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

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

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

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

例如,如果你在Linux上打印了一个“足够长”的字符串,没有换行符( \n ),它可能会被写入,就好像它有一个换行符(因为它超过了缓冲区)。 您也可能会发现缓存大小在标准输出,管道和文件之间有所不同。

依赖未指定的行为是非常糟糕的 ,所以当你真的需要写入字节时使用flush()

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

Windows和Linux有非常不同的控制台输出驱动程序。 在Linux中,输出被缓冲,直到\ n出现在程序的情况下。

如果你想强制缓冲区手动刷新使用

 import sys sys.stdout.flush() 

这已经在其他地方有答案,但我会在下面总结。

  1. 在Windows和Linux上的不同行为的原因是由于打印命令的实现方式(如在eryksun的评论中指出)。 你可以在这里和这里得到更多的信息。

  2. 这可以通过python在很多方面进行补救。 更多的在这里 。

这个问题从2011年就已知,请参阅这个Python错误#11633

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

为了考虑到行为差异,找到的解决方案是更新文档,以便将下面的句子加入黑体:

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

值得一提的是:

Guido说这是它应该做的,“需要冲洗的应用程序应该调用flush()”。 所以代码更改被拒绝。