来自Python脚本的无序输出

13 浏览
0 Comments

来自Python脚本的无序输出

Python解释器在sys.stdout上是否默认启用了输出缓冲?

如果答案是肯定的,那么有哪些禁用它的方法?

迄今为止的建议:

  1. 使用-u命令行开关
  2. sys.stdout包装在在每次写入后刷新的对象中
  3. 设置PYTHONUNBUFFERED环境变量
  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

在执行期间,是否还有其他方法可以在sys/sys.stdout中以编程方式设置一些全局标志?


如果您只想在使用print时在特定写入后刷新,请参阅如何刷新print函数的输出?

0
0 Comments

文章标题:Python中print函数输出乱序的原因及解决方法

在Python中,print函数输出乱序的问题是由于缓冲机制引起的。当我们使用print函数输出内容时,内容首先会被缓存起来,然后在合适的时机才会被写入到输出流中。这种缓冲机制的存在是为了提高程序的性能,减少IO操作的次数。

然而,在某些情况下,我们希望立即将内容输出到屏幕上,而不是等待缓冲区满或者遇到换行符时才输出。例如,当我们需要实时显示程序的运行进度或者调试信息时,就需要禁用缓冲机制,使得print函数能够立即输出内容。

Python提供了一个解决方案,即使用print函数的flush参数。从Python 3.3版本开始,我们可以在print函数中使用flush=True来禁用缓冲机制,使得内容立即输出到屏幕上。

下面是一个示例代码:

print('Hello World!', flush=True)

通过设置flush=True,print函数将立即将内容输出到屏幕上,而不需要等待缓冲区满或者遇到换行符。

需要注意的是,禁用缓冲机制会带来一定的性能损耗,因此在使用flush参数时需谨慎。只有在特定需要实时显示输出内容的情况下,才建议禁用缓冲机制。

总结起来,Python中print函数输出乱序的问题可以通过禁用缓冲机制来解决,即使用print函数的flush参数,并将其设置为True。这样可以保证内容立即输出到屏幕上,而不需要等待缓冲区满或者遇到换行符。但需要注意,禁用缓冲机制会带来一定的性能损耗,因此在使用时需谨慎权衡。

0
0 Comments

问题的出现原因:

- Python的print语句默认会进行输出缓冲,即将输出存储在缓冲区中,而不是立即将其发送到终端或管道。

- 这种缓冲机制在某些情况下会导致问题,特别是在输出被重定向到管道或文件时。

解决方法:

- 可以通过使用python -u命令行选项或设置环境变量PYTHONUNBUFFERED来跳过整个Python进程的缓冲。

- 也可以将sys.stdout替换为另一个流,这个流在每次调用后都会执行刷新操作。具体实现可以使用以下代码:

class Unbuffered(object):
   def __init__(self, stream):
       self.stream = stream
   def write(self, data):
       self.stream.write(data)
       self.stream.flush()
   def writelines(self, datas):
       self.stream.writelines(datas)
       self.stream.flush()
   def __getattr__(self, attr):
       return getattr(self.stream, attr)
import sys
sys.stdout = Unbuffered(sys.stdout)
print 'Hello'

- 原始的sys.stdout仍然可以通过sys.__stdout__访问,以防需要它。

其他注意事项:

- 输出缓冲的行为取决于输出流的类型,如果输出流是终端,则在每次遇到换行符时会执行刷新操作,但如果输出流是管道,则会进行缓冲。

- 在Cpython中,当使用for line in sys.stdin:迭代输入时,循环体运行之前会收集多行输入,这会表现得像缓冲一样。可以改为使用while true: line = sys.stdin.readline()来避免这种情况。

- 禁用输出缓冲的后果是性能提升,因为写入到控制台的速度相对较慢,所以批量写入可以减少开销。

- 可以使用iter()代替while循环,例如:for line in iter(pipe.readline, ''):。在Python 3中,使用for line in pipe:会尽快生成结果。

- 在一些特殊情况下,如在IDLE中,上述解决方法可能不起作用,因为sys.stdout已经被替换为其他对象,不允许执行刷新操作。

- 在运行CGI Python脚本时,这种解决方法非常有用,特别是在IIS上。同时,结合在web.config中设置responseBufferLimit="0",可以消除脚本输出的其他缓冲效果。

最后,如果想了解更多关于流缓冲的信息,可以参考一篇文章:eklitzke.org/stdout-buffering

0
0 Comments

在Python中,当我们使用print()函数打印输出时,有时会遇到输出不及时的问题。这是因为默认情况下,print()函数将输出缓存在内存中,并在一定条件下才将其刷新到终端上。这可能会导致输出的顺序混乱或延迟显示。

为了解决这个问题,可以使用以下方法之一:

1. 在Python 3.3及以后的版本中,可以在print()函数中添加flush=True参数,强制将输出立即刷新到终端上。例如:print("Hello", flush=True)

2. 在Python 3中,可以通过重新打开sys.stdout文件描述符来实现无缓冲输出。具体做法是,将sys.stdout重新指向一个以写模式打开的文件,同时设置缓冲区大小为0。这可以通过以下代码实现:

# 重新以写模式打开stdout文件描述符,并设置缓冲区大小为0(无缓冲)
import io, os, sys
try:
    # Python 3,以二进制方式打开文件,然后包装为TextIOWrapper,设置write_through参数为True
    sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True)
    # 如果只在换行符上刷新即可,可以在Python 3.7及更高版本中直接调用以下方法:
    # sys.stdout.reconfigure(line_buffering=True)
except TypeError:
    # Python 2
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

需要注意的是,上述代码只适用于Python 3中的情况。对于Python 2,可以使用os.fdopen()函数重新打开sys.stdout文件描述符,并设置缓冲区大小为0。

总结起来,要解决print()函数输出不及时的问题,可以通过在print()函数中添加flush=True参数,或者重新打开sys.stdout文件描述符来实现无缓冲输出。这样可以确保输出立即刷新到终端上,避免延迟显示或顺序混乱的问题。

0