我了解到程序中的I/O默认是有缓存的,也就是说它们会从临时存储中提供给请求的程序。
我明白缓存可以提高IO性能(可能是通过减少系统调用实现)。
我看到过禁用缓存的示例,例如C语言中的setvbuf
。那么这两种模式之间有什么区别,应该在何时使用其中一种而不是另一种呢?
我了解到程序中的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 |
+---------------------------------------+
当你有大量字节序列准备写入磁盘并且想要避免在中间进行额外的复制时,你需要无缓冲输出。
缓冲输出流将把写入结果累计到一个中间缓冲区中,仅在累积足够的数据(或者请求flush()
)时将其发送到操作系统文件系统。这减少了文件系统调用的数量。由于对大多数平台而言,与短memcpy
相比,文件系统调用可能很昂贵,因此在执行大量小写入时,缓冲输出是一种净优势。当您已经有大型缓冲区要发送时,无缓冲输出通常更好-- 复制到中间缓冲区不会进一步减少操作系统调用的数量,并引入了额外的工作。
无缓冲输出与确保数据到达磁盘没有任何关系; 这个功能由flush()
提供,并且适用于缓冲和无缓冲流。无缓冲IO写入不保证数据已到达物理磁盘--如果操作系统文件系统希望,它可以无限期地保留您的数据的副本,从不将其写入磁盘。只有在调用flush()
时,它才需要将其提交到磁盘(请注意,close()
将代表您调用flush()
)。
flush()
方法能够保证数据被写入磁盘吗?我认为它只是将数据传递到磁盘的缓存区。 - jrdiokoO_SYNC
来确保写入的保证。 - moshbear
FILE
对象(流)的内部缓冲区与fgets
所需的缓冲区参数完全不同。在我编写了一些代码来弄清楚它之前,这让我困惑了数小时。QAQ - Rick