缓冲与无缓冲IO


83

我了解到,默认情况下,程序中的I / O是经过缓冲的,即它们是从临时存储提供给请求程序的。我知道缓冲可以提高IO性能(也许通过减少系统调用)。我已经看到了禁用缓冲的示例,例如setvbuf在C语言中。这两种模式之间有什么区别?什么时候应该在另一种之上使用?

Answers:


123

每当需要确保继续之前已写入输出时,都需要无缓冲的输出。一个示例是C运行时库下的标准错误-默认情况下通常不缓冲。由于(希望)很少发生错误,因此您想立即了解它们。另一方面,缓冲标准输出,因为它假定会有更多的数据通过它。

另一个示例是日志记录库。如果您的日志消息保存在进程的缓冲区中,并且进程转储了内核,则很有可能永远不会写入输出。

另外,不仅是最小化的系统调用,还包括磁盘I / O。假设某个程序一次读取一个字节的文件。使用无缓冲输入,即使每个字节可能都必须读取一个完整的块(磁盘硬件本身可能有缓冲区,但您仍然要出门到磁盘控制器),每个字节您都将进入(相对很慢)磁盘这将比内存访问慢。

通过缓冲,整个块立即读入缓冲区,然后将各个字节从(内存中的,速度非常快的)缓冲区中传递给您。

请记住,缓冲可以采用多种形式,例如以下示例:

+-------------------+-------------------+
| Process A         | Process B         |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
|               OS caches               | Operating system buffers
+---------------------------------------+
|      Disk controller hardware cache   | Disk hardware buffers
+---------------------------------------+
|                   Disk                |
+---------------------------------------+

该图很棒。值得一提的是,FILE对象(流)的内部缓冲区与fgets所需的缓冲区参数完全不同。在我写一些代码弄清楚之前,这让我困惑了几个小时。QAQ
瑞克,

35

当您已经准备好要写入磁盘的大量字节序列时,想要无缓冲的输出,并且想要避免在中间的第二个缓冲区中多余的复制

缓冲的输出流会将写入结果累积到中间缓冲区中,仅在累积(或flush()请求)足够的数据时才将其发送到OS文件系统。这减少了文件系统调用的次数。由于在大多数平台上文件系统调用的成本可能很高(与short相比memcpy),因此在执行大量的小写操作时,缓冲输出是赢家。当您已经有较大的缓冲区要发送时,无缓冲输出通常更好—复制到中间缓冲区不会进一步减少OS调用的次数,并且会带来更多工作。

无缓冲输出与确保数据到达磁盘无关。该功能由提供flush(),可在缓冲流和非缓冲流上使用。无缓冲的IO写入不能保证数据已到达物理磁盘-OS文件系统可以无限期地无限期保留数据副本,如果需要,也可以永远不将其写入磁盘。只需在调用时将其提交到磁盘即可flush()。(请注意,close()它将flush()代表您致电)。


调用是否可以flush()保证将其写入磁盘?我以为只是将其传递到磁盘缓冲区中。
jrdioko

2
您需要O_SYNC确保保证写入。
moshbear 2011年

未缓冲的IO关于写入磁盘的信息。因此,对于winapi,术语无缓冲(没有中间缓冲区,而是直接写入磁盘)可通过FILE_FLAG_NO_BUFFERING和FILE_FLAG_WRITE_THROUGH调用CreateFile以确保数据在每次写入后直接进行持久化。对于其他操作系统,我知道。
马丁·科西基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.