实时输出流打印 - 缓冲问题与解决方案

Output Buffering in Realtime - Question and Solution

Posted by zihengCat on 2018-07-20

前言

现代程序设计语言(尤其是动态脚本语言)的I/O库在设计时,大多会针对输出流「Output Stream」做缓冲「Buffering」机制。其目的是为了最小化「Minimize」I/O操作。众所周知,I/O操作是非常慢、非常费时的,例如:读写磁盘,访问网络,打印信息到控制台「Console」。

缓冲「Buffering」机制

在执行I/O操作时,程序会在内存中开辟出一块合适的空间,用作缓存「Buffer」,在缓存区域收到一定数据量或触发事件flush()前,不会真正执行磁盘读写I/O操作。

不同语言下的实时输出流

I/O缓冲机制无疑是优秀的设计,但有时候,这一机制也会我们带来一定的麻烦(比如,无法实时查看Jenkins持续集成 CI 系统下的控制台信息输出)。我们需要某些方法能做到实时输出流打印。

Python语言

Python中,做到实时输出的方法还是很多的。

使用Python解释器提供的-u参数。

$ python -u <script.py>

代码清单:Python语言使用-u参数

设置环境变量PYTHONUNBUFFERED的值为1

$ export PYTHONUNBUFFERED=1

代码清单:设置环境变量PYTHONUNBUFFERED

使用fileObject.flush()。在 Python3.3 之后,我们可以直接在print()函数中指定flush参数。在 Python2 中,我们也可以通过from __future__ import print_function来使用新版本打印函数。

import sys
sys.stdout.write("...")
# 立即刷新缓冲区
sys.stdout.flush()

代码清单:使用flush()刷新缓冲区

Ruby语言

对于Ruby语言,我们可以直接设置STDOUT.sync,命令其做实时输出流打印。

STDOUT.sync = true

代码清单:ruby实时输出流打印设置

Perl语言

perl脚本语言中,也可以设置实时输出流打印。

autoflush STDOUT 1;

代码清单:perl实时输出流打印设置

参考资料