C - "写入"函数的正确缓冲区大小是多少?



我使用低级I/O函数"write"在代码(Linux上的C语言)中将一些数据写入磁盘。首先,我将数据累积在内存缓冲区中,然后在缓冲区满时使用"write"将数据写入磁盘。那么"写"的最佳缓冲区大小是多少?根据我的测试,它并不是越大越快,所以我在这里寻找答案。

写入文件系统块大小的倍数可能有一些优势,尤其是当您在原地更新文件时。如果向文件写入的块少于部分,操作系统必须读取旧块,合并新内容,然后将其写出。如果按顺序快速写入小块,则不一定会发生这种情况,因为更新将在稍后刷新的内存缓冲区上进行。尽管如此,如果每次写入操作都不填充一个块(以及一个正确对齐的块:偏移量是块大小的倍数),偶尔可能会引发一些效率低下的情况。

这种转会规模的问题不一定会随着mmap而消失。如果映射一个文件,然后将一些数据memcpy到映射中,则会使页面变脏。该页面必须在以后的某个时间刷新:不确定何时刷新。如果你制作了另一个接触同一页的memcpy,那么该页现在可能是干净的,而你又让它变脏了。所以它被写了两次。一个页面大小的倍数的页面对齐副本将是一种方法。

您希望它是CPU页面大小的倍数,以便尽可能有效地使用内存。

但理想情况下,您希望使用mmap,这样您就不必自己处理缓冲区了。

您可以使用<stdio.h> 中定义的BUFSIZ

否则,请使用页面大小sysconf(_SC_PAGESIZE)的小倍数(例如该值的两倍)。大多数Linux系统都有4K字节的页面(通常与文件系统块大小相同或是文件系统块的小倍数)。

正如其他人回答的那样,使用mmap(2)系统调用可能会有所帮助。GNU系统(例如Linux)有一个扩展:fopen的第二个模式字符串可能包含后一个m,当这种情况发生时,GNU libc会尝试mmap

如果您处理的数据几乎和您的RAM一样大(或一半),您可能还需要使用madvise(2)来微调mmap的性能。

另请参阅与您的问题非常相似的答案。(您可以使用64K字节作为合理的缓冲区大小)。

"最佳"大小在很大程度上取决于底层文件系统。

statfstat调用填充一个数据结构struct stat,该数据结构包括以下字段:

blksize_t st_blksize; /* blocksize for file system I/O */

操作系统负责用write()块的"良好大小"填充此字段。但是,使用"对齐良好"的内存(例如malloc调用的结果)调用write()也很重要。实现这一点的最简单方法是使用提供的<stdio.h>流接口(带有FILE *对象)。

与这里的其他答案一样,使用mmap在许多情况下也可能非常快。请注意,它不太适合某些类型的流(例如,套接字和管道)。

这取决于RAM、VM等的数量以及写入的数据量。更一般的答案是对什么缓冲区最适合您处理的负载进行基准测试,并使用最适合的缓冲区。

最新更新