写入控制台时,在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上根本就没有。 我们可以使用-u
closures缓冲(在这种情况下,Linux上的脚本与Windows上的脚本具有相同的行为)。 该文件说:
-u强制stdin,stdout和stderr完全无缓冲。
所以实际上,并没有说没有-u
stdin
和stdout
被caching了。 因此我的问题是:
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()
这已经在其他地方有答案,但我会在下面总结。
在Windows和Linux上的不同行为的原因是由于打印命令的实现方式(如在eryksun的评论中指出)。 你可以在这里和这里得到更多的信息。
这可以通过python在很多方面进行补救。 更多的在这里 。
这个问题从2011年就已知,请参阅这个Python错误#11633
打印功能不做任何缓冲。 它写入的文件对象可能。 即使sys.stdout
可能也可能不会。
为了考虑到行为差异,找到的解决方案是更新文档,以便将下面的句子加入黑体:
file参数必须是带有write(string)方法的对象; 如果它不存在或None,将使用sys.stdout。 输出缓冲由文件决定。
值得一提的是:
Guido说这是它应该做的,“需要冲洗的应用程序应该调用flush()”。 所以代码更改被拒绝。