禁用输出缓冲

在Python的解释器中sys.stdout默认启用输出缓冲吗?

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

目前的建议:

  1. 使用-u命令行开关
  2. sys.stdout包装在每次写入后都会刷新的对象中
  3. 设置PYTHONUNBUFFERED环境变量
  4. # EYZ0

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

357220 次浏览

从# EYZ0:

你可以整体跳过缓冲 python进程使用python -u 或通过 设置环境变量 PYTHONUNBUFFERED . < / p >

你也可以替换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'

是的,它是。

您可以在命令行上使用“-u”开关禁用它。

或者,您可以在sys. flush()上调用。每次写入时的Stdout(或使用自动执行此操作的对象将其包装)

是的,默认启用。当调用python时,可以在命令行上使用-u选项禁用它。

获得无缓冲输出的一种方法是使用sys.stderr而不是sys.stdout,或者简单地调用sys.stdout.flush()显式地强制执行写操作。

你可以很容易地重定向打印的所有内容:

import sys; sys.stdout = sys.stderr
print "Hello World!"

或者为特定的print语句重定向:

print >>sys.stderr, "Hello World!"

要重置stdout,你可以这样做:

sys.stdout = sys.__stdout__

您可以创建一个未缓冲的文件,并将该文件分配给sys.stdout。

import sys
myFile= open( "a.log", "w", 0 )
sys.stdout= myFile

你不能神奇地改变系统提供的标准输出;因为它是由操作系统提供给python程序的。

# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
import io, os, sys
try:
# Python 3, open as binary, then wrap in a TextIOWrapper with write-through.
sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True)
# If flushing on newlines is sufficient, as of 3.7 you can instead just call:
# sys.stdout.reconfigure(line_buffering=True)
except TypeError:
# Python 2
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

工作人员:“塞巴斯蒂安”,在Python邮件列表的某个地方。

您还可以使用fcntl动态更改文件标志。

fl = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL)
fl |= os.O_SYNC # or os.O_DSYNC (if you don't care the file timestamp updates)
fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, fl)
def disable_stdout_buffering():
# Appending to gc.garbage is a way to stop an object from being
# destroyed.  If the old sys.stdout is ever collected, it will
# close() stdout, which is not good.
gc.garbage.append(sys.stdout)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)


# Then this will give output in the correct order:
disable_stdout_buffering()
print "hello"
subprocess.call(["echo", "bye"])

不拯救旧的系统。Stdout, disable_stdout_buffering()不是幂等的,多次调用将导致这样的错误:

Traceback (most recent call last):
File "test/buffering.py", line 17, in <module>
print "hello"
IOError: [Errno 9] Bad file descriptor
close failed: [Errno 9] Bad file descriptor

另一种可能性是:

def disable_stdout_buffering():
fileno = sys.stdout.fileno()
temp_fd = os.dup(fileno)
sys.stdout.close()
os.dup2(temp_fd, fileno)
os.close(temp_fd)
sys.stdout = os.fdopen(fileno, "w", 0)

(附加到gc。垃圾并不是一个好主意,因为它是放置不可释放循环的地方,您可能需要检查它们。)

变种,工作不崩溃(至少在win32;Python 2.7, ipython 0.12)然后随后调用(多次):

def DisOutBuffering():
if sys.stdout.name == '<stdout>':
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)


if sys.stderr.name == '<stderr>':
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)

我宁愿把我的答案放在如何冲洗输出打印功能?Python's的打印函数,当它'被调用时刷新缓冲区?中,但由于它们被标记为这个答案的副本(这是我不同意的),我将在这里回答。

从Python 3.3开始,print()支持关键字参数"flush" (看文档):

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

(我已经发表了一条评论,但不知怎么弄丢了。所以,再次:)

    正如我注意到的,CPython(至少在Linux上)的行为取决于输出的位置。如果转到tty,则在每个'\n' '之后刷新输出
    如果它进入管道/进程,那么它是缓冲的,你可以使用基于flush()的解决方案或上面推荐的- u选项
  1. 与输出缓冲略有关系:
    如果用

    遍历输入中的行 < p > # EYZ0
    …< / p > < /李>

,那么CPython的中的实现将收集一段时间的输入,然后为一堆输入行执行循环体。如果您的脚本要为每个输入行编写输出,这可能看起来像输出缓冲,但实际上是批处理,因此,flush()等技术都无法帮助实现这一点。 有趣的是,在pypy中没有这种行为。 为了避免这种情况,可以使用

< p > <代码>而真实的: 代码行= sys.stdin.readline () < / > < / p >

以下代码适用于Python 2.6、2.7和3.2:

import os
import sys
buf_arg = 0
if sys.version_info[0] == 3:
os.environ['PYTHONUNBUFFERED'] = '1'
buf_arg = 1
sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg)

你也可以使用stdbuf实用程序运行Python:

# EYZ0

这与Cristóvão D. Sousa的回答有关,但我还不能评论。

使用Python 3flush关键字参数以使总是具有未缓冲输出的直接方法是:

import functools
print = functools.partial(print, flush=True)

然后,print将始终直接刷新输出(除了给出flush=False)。

注意,(a)这只回答了部分问题,因为它没有重定向所有输出。但是我猜print是在python中创建输出到stdout/stderr的最常用方法,所以这两行可能涵盖了大多数用例。

注意(b)它只在定义它的模块/脚本中工作。这在编写模块时很好,因为它不会与sys.stdout混淆。

Python 2没有提供flush参数,但是您可以模拟一个Python 3类型的print函数,如这里所述。

可以用一个调用flush的方法来覆盖sys.stdout只有 write方法。建议的方法实现如下所示。

def write_flush(args, w=stdout.write):
w(args)
stdout.flush()

w参数的默认值将保留原始的write方法引用。定义了 write_flush,原始的write可能会被覆盖。

stdout.write = write_flush

代码假设以from sys import stdout的方式导入stdout

在Python 3中,你可以修补打印函数,以始终发送flush=True:

_orig_print = print


def print(*args, **kwargs):
_orig_print(*args, flush=True, **kwargs)

正如在评论中指出的,你可以通过将flush参数绑定到一个值来简化这一点,通过functools.partial:

print = functools.partial(print, flush=True)