禁用输出缓冲

2024-11-19 08:38:00
admin
原创
10
摘要:问题描述:Python 解释器中默认启用输出缓冲吗sys.stdout?如果答案是肯定的,那么有哪些方法可以禁用它?目前的建议:使用-u命令行开关包装sys.stdout一个在每次写入后刷新的对象设置PYTHONUNBUFFERED环境变量sys.stdout = os.fdopen(sys.stdout.f...

问题描述:

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

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

目前的建议:

  1. 使用-u命令行开关

  2. 包装sys.stdout一个在每次写入后刷新的对象

  3. 设置PYTHONUNBUFFERED环境变量

  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

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


如果您只是想在使用后刷新print,请参阅如何刷新打印函数的输出?。


解决方案 1:

来自Magnus Lycka 在邮件列表上的回答:

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'

解决方案 2:

我宁愿把我的答案放在如何刷新打印函数的输出?或者在调用时刷新缓冲区的 Python 打印函数?中,但由于它们被标记为重复(我不同意),所以我将在这里回答。

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

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

解决方案 3:

# 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)

致谢:“Sebastian”,来自 Python 邮件列表的某处。

解决方案 4:

是的。

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

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

解决方案 5:

这与 Cristóvão D. Sousa 的回答有关,但我还无法发表评论。

为了始终获得无缓冲输出,使用Python 3flush的关键字参数的直接方法是:

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

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

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

注意 (b) 它只在你定义它的模块/脚本中起作用。这在编写模块时很有用,因为它不会干扰sys.stdout

Python 2不提供该flush参数,但您可以模拟 Python 3 类型的print函数,如下所述https://stackoverflow.com/a/27991478/3734258

解决方案 6:

以下内容适用于 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)

解决方案 7:

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"])

如果不保存旧的 sys.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.garbage 并不是一个好主意,因为不可释放的循环被放在这里,你可能需要检查这些循环。)

解决方案 8:

在 Python 3 中,你可以对 print 函数进行 monkey-patch,使其始终发送 flush=True:

_orig_print = print

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

正如评论中指出的那样,您可以通过将 flush 参数绑定到某个值来简化此过程,方法是functools.partial

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

解决方案 9:

是的,默认情况下它是启用的。您可以在调用python时在命令行中使用-u选项来禁用它。

解决方案 10:

您还可以使用stdbuf实用程序运行 Python :

stdbuf -oL python <script>

解决方案 11:

只能用调用 的方法覆盖 方法write。建议的方法实现如下。sys.stdout`flush`

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

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

stdout.write = write_flush

代码假定以stdout这种方式导入from sys import stdout

解决方案 12:

您还可以使用 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)

解决方案 13:

获取无缓冲输出的一种方法是使用sys.stderr而不是sys.stdout或简单地调用sys.stdout.flush()以明确强制进行写入。

您可以轻松地重定向打印的所有内容:

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

或者只针对特定语句进行重定向print

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

要重置标准输出,您只需执行以下操作:

sys.stdout = sys.__stdout__

解决方案 14:

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

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

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

解决方案 15:

不会崩溃的变体(至少在 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)

解决方案 16:

(我曾发表过评论,但不知为何丢失了。所以,再说一遍:)

  1. 我注意到,CPython(至少在 Linux 上)的行为会根据输出的位置而有所不同。如果输出到 tty,则输出会在每次 ' 之后刷新。`
    '`

如果输出到管道/进程,则输出会被缓冲,您可以使用flush()基于的解决方案或上面推荐的-u选项。

  1. 与输出缓冲稍微相关:

如果你使用

for line in sys.stdin:

...

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

`while True:
line=sys.stdin.readline()`

...

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用