了解 fwrite() 的缓冲行为
Posted
技术标签:
【中文标题】了解 fwrite() 的缓冲行为【英文标题】:Understanding buffering behavior of fwrite() 【发布时间】:2012-05-05 20:57:36 【问题描述】:我正在使用函数调用fwrite()
将数据写入 Linux 上的管道。
之前,fwrite()
被反复调用以获取小块数据(平均 20 字节),而缓冲留给了fwrite()
。对进程的 strace 显示一次写入了 4096 字节的数据。
原来这个编写过程是我程序的瓶颈。所以我决定将代码中的数据缓冲成 64KB 的块,然后使用fwrite()
一次写入整个块。我使用setvbuf()
将 FILE* 指针设置为“无缓冲”。
性能提升没有我预期的那么显着。
更重要的是,strace
输出显示数据仍一次写入 4096 个字节。有人可以向我解释这种行为吗?如果我用 64KB 的数据调用 fwrite()
,为什么它一次只写入 4096 个字节?
是否有替代fwrite()
使用 FILE* 指针将数据写入管道的方法?
【问题讨论】:
@Shailesh_Tainwala:您可能正在用 C++ 编写代码,但这是一个 C 问题,而不是 C++。fwrite()
是一个 c 函数,而不是 c++ 函数。我在您的问题中添加了一个 c 标签,这样您就可以获得更广泛的受众。
【参考方案1】:
如果您想更改缓冲行为,您必须在 fopen
之后立即执行此操作(或在任何 I/O 之前,对于标准文件句柄 stdin
、stdout
、stderr
)。您也不想禁用缓冲并尝试自己管理缓冲区;相反,请将您的 64K 缓冲区指定为 setvbuf
,以便正确使用它。
如果你真的想手动管理缓冲,不要使用stdio
;使用较低级别的open
、write
和close
调用。
【讨论】:
【参考方案2】:4096 来自作为管道基础的 Linux 机器。它发生在两个地方。一是管道的容量。在旧版本的 Linux 上,容量是一个系统页面,在 32 位 i386 机器上是 4096 字节。 (在更现代的 Linux 版本上,容量为 64K。)
您将遇到 4096 字节问题的另一个地方是定义的常量PIPE_BUF
,即保证被原子处理的字节数。在 Linux 上,这是 4096 字节。此限制的含义取决于您是否将管道设置为阻塞或非阻塞。为所有血腥细节发送man -S7 pipe
。
如果您尝试高速交换大量数据,您可能需要重新考虑使用管道。您在 Linux 机器上,因此可以选择共享内存。您可以使用管道作为信号机制来发送相对少量的数据。
【讨论】:
另一个可能的 Linux 唯一选项是使用 open() 和 splice() 而不是 fwrite()。以上是关于了解 fwrite() 的缓冲行为的主要内容,如果未能解决你的问题,请参考以下文章
Linux 和 Windows 之间 fwrite 的不同行为
fwrite 消耗所有 MemFree,fflush 不起作用?
缓冲文件系统(fopen/fread/fwrite)和非缓冲文件系统(open/read/write)
缓冲文件系统(fopen/fread/fwrite)和非缓冲文件系统(open/read/write)