当写入控制台时,在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
- 选项stdin
和stdout
都会被缓冲。因此我的问题是:
stdout
将被缓冲,无论哪个操作系统?至少在Windows和Linux中就是这种情况。 我主要担心的是(正如一些答案所假设的)当刷新信息时,但是如果stdout
没有被缓冲,那么它可能是一个严重的性能损失而且不应该依赖它。
编辑:值得注意的是,对于Python3,Linux和Windows的行为是相同的(但这并不奇怪,因为行为是由{{1的参数显式配置的}} - 方法)
答案 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)
其他地方已有答案,但我将在下面进行总结。
答案 3 :(得分:1)
此问题自2011年起就已知,请参阅此Python bug issue #11633
打印功能不进行任何缓冲。它写入的文件对象可能。即使sys.stdout
可能会也可能不会。
考虑到行为的差异,找到的解决方案是更新文档,以便以粗体包含以下句子:
file参数必须是带有write(string)方法的对象;如果它 不存在或无,将使用sys.stdout。 输出缓冲是 由文件确定。
值得注意的是:
Guido说它应该做的事情是“需要刷新的应用程序应该调用flush()。”因此,代码更改被拒绝。