Language agnostic 缓冲与非缓冲IO

Language agnostic 缓冲与非缓冲IO,language-agnostic,io,buffering,Language Agnostic,Io,Buffering,我了解到,默认情况下,程序中的I/O是缓冲的,也就是说,它们是从临时存储器提供给请求程序的。 我知道缓冲可以提高IO性能(可能是通过减少系统调用)。我看到过禁用缓冲的示例,如C中的setvbuf。这两种模式之间的区别是什么,以及何时应该使用一种模式而不是另一种模式?您希望在继续之前确保已写入输出时无缓冲输出。一个例子是C运行时库下的标准错误-默认情况下这通常是无缓冲的。因为(希望)错误很少发生,所以您希望立即了解它们。另一方面,标准输出是缓冲的,因为它假设将有更多的数据通过它 另一个例子是日志库

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

您希望在继续之前确保已写入输出时无缓冲输出。一个例子是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                |
+---------------------------------------+

当您已经准备好写入磁盘的大字节序列时,您需要无缓冲的输出,并希望<强>避免在中间的第二个缓冲区中添加额外的拷贝<强>。p> 缓冲的输出流将把写入结果累积到中间缓冲区中,仅当累积了足够的数据(或请求了

flush()
时)才将其发送到操作系统文件系统。这减少了文件系统调用的数量。由于在大多数平台上,文件系统调用可能非常昂贵(与short
memcpy
相比),因此在执行大量小写操作时,缓冲输出是一个巨大的优势。当您已经有大的缓冲区要发送时,无缓冲输出通常会更好——复制到中间缓冲区不会进一步减少操作系统调用的数量,并且会引入额外的工作


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

调用
flush()
会保证写入磁盘吗?我认为这只是将其传递到磁盘的缓冲区。您需要
O_SYNC
来确保写入。无缓冲IO可能会被写入磁盘。因此,winapi的术语为“无缓冲”(无中间缓冲区,但直接写入磁盘),您使用FILE_FLAG_no_BUFFERING和FILE_FLAG_WRITE_THROUGH调用CreateFile,以确保数据在每次写入后直接进行持久化。对于其他一些操作系统,我不知道。这个图表非常棒。值得一提的是,
文件
对象(流)的内部缓冲区与
fgets
所需的缓冲区参数完全不同。这让我困惑了好几个小时,然后我写了一些代码来解决它。质量保证