我在我的代码中使用底层I/O函数'write'将一些数据写入磁盘(Linux系统的C语言)。首先,我将数据累积在内存缓冲区中,然后当缓冲区满时使用'write'将数据写入磁盘。那么什么是最好的'write'缓冲区大小呢?根据我的测试,不是越大越快,所以我来寻找答案。
为了尽可能高效地使用内存,您需要将其设置为CPU页面大小的倍数。
但最好使用mmap,这样您就永远不必自己处理缓冲区。
mmap
映射所有数据肯定没问题。您可以使用madvise
进行微调。 - Basile Starynkevitchmalloc
放置了一些东西。如果mmap代替缓冲流I/O是一个好主意,也许glibc会以这种方式实现FILE *
流。 - Kazmmap
,例如在包含 m
的模式下使用 fopen
。 - Basile Starynkevitch<stdio.h>
中定义的BUFSIZ
。sysconf(_SC_PAGESIZE)
的小倍数(例如,该值的两倍)。大多数Linux系统都有4K字节的页面(通常与文件系统块大小相同或是其小倍数)。m
,当发生这种情况时,GNU libc尝试进行mmap
。mmap
的性能。在进行写操作时,尤其是就地更新文件时,使用文件系统块大小的倍数可能会有一些优势。如果你向文件中写入少于一个块部分的内容,则操作系统必须读取旧块,将新内容合并到其中,然后写出。如果你按顺序快速写入小块,则不一定会发生这种情况,因为更新将在稍后刷新的内存缓冲区上完成。但是,如果你没有每次写操作都填满(并且填满一个正确对齐的块:以块大小的倍数偏移),偶尔会触发一些效率低下的情况。
传输大小的这个问题并不一定会通过映射消失。如果你映射一个文件,然后memcpy
一些数据到映射中,你就使一个页面变脏了。该页必须在某个时间点之后刷新:但是具体什么时间点是不确定的。如果你再进行另一个memcpy
操作,并且触及同一页,则该页面现在可能已经是干净状态,而你又使它变脏了。因此,它将被写入两次。对齐页面大小并且是页面大小倍数的复制将是最好的方式。
"最佳"大小很大程度上取决于底层文件系统。
stat
和 fstat
调用填充一个数据结构 struct stat
,其中包括以下字段:
blksize_t st_blksize; /* blocksize for file system I/O */
<stdio.h>
流接口(使用FILE *
对象)来实现这一点。writev
来实现类似的效果,但通常这样做的工作量更大,甚至内核也必须执行相同的内存复制操作。) - torekst_blksize
返回的值实际上不是最优的,那么内核就没有履行它的承诺。 :-) - torek这取决于RAM,VM等的数量以及要写入的数据量。更一般的答案是测试何种缓冲区对你所处理的负载效果最佳,然后使用最佳的方案。