flush it! 关于数据缓冲区
之前对python的标准输入输出关注不多,所以在碰到flush的时候有了诸多疑惑。
本文记录了和flush方法相关的缓冲的相关内容,供学习参考。
数据缓冲
在计算机科学中,数据缓冲(data buffer)是一个当数据需要从一个地方移到另一个地方时,用来暂时保存数据的物理区域。常见的情况是,当输入数据(例如从麦克风)或者在输出数据到输出设备(例如扬声器)之前,数据会被存储到buffer中。不过,在计算机程序之间交换数据也会使用到buffer。可以将其与电信通信中的buffer进行对比。缓冲可以通过硬件中固定的存储位置实现,也可以在软件中利用虚拟的数据缓冲来实现——只要将其指向一个在物理存储设备上的地址就可以。在所有情况下,存储在数据缓冲中的数据都存储在物理存储介质中。大部分的缓冲应用在软件中,一般使用RAM来存储临时数据,因为它相较硬盘而言有更快的存取速度。缓冲经常用在接收数据和处理数据的速度不一样的场景,或者接收、处理数据速度可变的场景,例如打印机队列以及在线视频流。
为了适应需要考虑时序的场景,缓冲在内存中使用了队列实现(FIFO)的算法,以一种速率将数据写入队列的同时,以另外一种速率读数据。
应用
缓冲常用来作为IO和硬件间的连接(conjunction),例如硬盘,从网络中发送或者接收数据,或是在扬声器上播放音频。这和过山车前排的长队是一样的。游客来玩过山车的频率通常是未知且变化的,但是过山车来了以后能够承载很大一批游客(load people in bursts)。排队的区域就像缓冲一样——给游客们等待过山车的一个临时的空间。一般而言,缓冲用FIFO的方法实现,然后按照数据输入的顺序对其进行输出。
缓冲能够通过允许同步操作增加应用的性能,例如更快速的文件读写,而不是在系统对硬件子系统存取数据时形成阻塞等,取而代之的是,操作系统能够马上返回正确的接口调用结果,允许应用在内核还在后台进行磁盘操作的同时继续工作。
缓冲带来的益处还包括当应用在读写的数据块大小与硬盘子系统的块大小不一致时,缓冲可以用来聚集许多的小数据块的读写操作,有时能够完全避免针对硬盘的存取操作,以此提高执行效率。
Buffer versus cache
高速缓存通常也作为缓冲区,反之亦然。但是,高速缓存运行的前提是相同的数据将被多次读取、写入的数据很快就会被读取,亦或是有很大概率进行多次读取,或者多次写入并以此形成一个较大的块。他们唯一的目的是减少对底层缓存的访问。缓存通常被设计为一个不可见的抽象层。
“磁盘高速缓存”或“文件高速缓存”保留数据中包含的统计信息,并在回写模式下,在超时期限内提交数据。缓冲没有这个用途。
缓冲区主要用于输入,输出,有时是临时的数据存储,这些数据可以是其他介质之间的路径,也可以是在顺序写入(或读取)数据之前以非顺序方式修改的数据。
Buffered vs unbuffered IO
只要在继续之前能确保输出已被写入,就可以使用无缓冲的输出。一个例子是C runtime library中的标准错误 - 默认情况下这通常是无缓冲的。由于错误不常发生,所以希望立即知道这些错误。另一方面,标准输出被缓冲,因为默认情况下它有更多的数据通过它。
另一个例子是日志库。如果你的日志消息被保存在你的进程中的缓冲区中,并且你的进程转储了核心(core dump),那么输出很有可能永远不会被写入。
另外,这不仅仅是最小化系统调用,还有最小化磁盘I / O。假设一个程序一次读取一个字节的文件,使用无缓冲输入时,不管怎样都必须读取整个数据块(磁盘硬件本身可能有缓冲区,但仍然要用到磁盘控制器,这将比内存访问慢得多)。
而通过缓冲,整个块被一次性地读入缓冲区,然后单个字节从(内存中,超级快)缓冲区传递给你。
sys.stdout.flush方法
python的标准输出是被缓冲的(buffered),意味着在输出到终端之前,会收集一些数据,写入标准输出中。调用sys.stdout.flush()方法会强制地清空buffer,会将buffer中的所有数据输出到终端中,即便通常情况下会在清空缓冲区之前等待。
> 本文编译自wikipedia和stackoverflow,错误之处欢迎指正~
参考资料:
Usage of sys.stdout.flush() method
http://en.wikipedia.org/wiki/Data_buffer
Buffered vs unbuffered IO
Python StringIO模块实现在内存缓冲区中读写数据
内存缓冲区解析