了解 fwrite() 的缓冲行为

Understanding buffering behavior of fwrite()

本文关键字:缓冲 fwrite 了解      更新时间:2023-10-16

我正在使用函数调用fwrite()将数据写入Linux上的管道。

早些时候,fwrite()被反复调用小块数据(平均20字节),缓冲留给fwrite()。 进程上的 Strace 显示一次写入 4096 字节的数据。

事实证明,这个写作过程是我程序的瓶颈。因此,我决定将代码中的数据缓冲为 64KB 的块,然后使用 fwrite() 一次写入整个块。我使用 setvbuf() 将 FILE* 指针设置为"无缓冲"。

性能改进并不像我预期的那么显着。

更重要的是,strace输出显示数据一次仍写入 4096 字节。有人可以向我解释这种行为吗?如果我调用具有 64KB 数据的fwrite(),为什么它一次只写入 4096 字节?

是否有替代使用 FILE* 指针将数据写入管道的fwrite()

4096 来自作为管道基础的 Linux 机器。它发生在两个地方。一是管道的容量。容量是旧版 Linux 上的一个系统页面,在 32 位 i386 机器上为 4096 字节。(在更现代的Linux版本上,容量为64K。

您将遇到 4096 字节问题的另一个地方是定义的常量PIPE_BUF,保证以原子方式处理的字节数。在 Linux 上,这是 4096 字节。此限制的含义取决于是否已将管道设置为阻止还是非阻塞。为所有血腥的细节做一个man -S7 pipe

如果您尝试以高速率交换大量数据,您可能需要重新考虑管道的使用。你使用的是 Linux 机器,所以共享内存是一种选择。可以使用管道发送相对少量的数据作为信号机制。

如果要更改缓冲行为,则必须在fopen之后立即执行此操作(或任何 I/O 之前,对于标准文件句柄stdinstdoutstderr)。 您也不想禁用缓冲并尝试自己管理缓冲区;相反,请指定要setvbuf的 64K 缓冲区,以便可以正确使用它。

如果确实要手动管理缓冲,请不要使用 stdio;请使用较低级别的 openwriteclose 调用。