write(2)的最佳缓冲区大小

5
假设我想使用write(2)系统调用将1 GB的数据写入到ext3 Linux文件系统上,并且在非常繁忙的环境下(许多类似的I/O并发处理),在不使用O_DIRECT打开标志或使用O_DIRECT时,使用区间[4 kB, 4 MB]内的最佳缓冲区大小是什么?
请不要提供“自己检查”的答案——我想从“文件系统”专家那里得到一些答案。

尝试进行基准测试。我认为大小在[16kb,1MB]范围内并不重要...而且我认为它对大小并不是非常敏感...(真正的瓶颈是磁盘硬件)。 - Basile Starynkevitch
你可以通过在文件上调用 stat(例如 stat("."))来获取文件系统的块大小。我认为结果会是一个很好的缓冲区大小。 - Some programmer dude
1
是的,我提供的范围很大。我知道4kb通常是文件系统上的页面大小和块大小。 - Basile Starynkevitch
如果您可以对齐到块大小并分配相应的内存,那么这将是一个不错的选择。不幸的是,对齐内存分配有时会遇到一些问题。MSVC提供了一个特定的函数(_aligned_malloc),还有另一个称为memalign的函数,但有时可能没有实现。 - Matt
当然,我假设有一个不错的大小,例如2的幂。我想读取8099字节大小的块是没有意义的。 - Basile Starynkevitch
显示剩余5条评论
3个回答

11

根据我的经验,答案更多地取决于底层设备和硬件,而不是文件系统本身--这是设备上的缓冲区缓存和设备编写小块等功能--但是,您永远不应该使用比文件系统块大小更小的大小进行写入(stat(.)--可能为约4kb)--同样,您也不应该超过CPU的L2/L3缓存大小,在许多情况下可以低至512kb

考虑到SSD设备和类似设备使用64kb作为操作单元,因此我建议使用64kb-128kb的缓冲区大小最为优化--这也与我的经验相对应,可实现最高吞吐量。


6

如评论中讨论的那样,我认为确切的大小并不太重要,只要满足以下条件:

  • 是文件系统大小的小倍数(参见Joachim Pileborg的评论建议stat(".")等)
  • 是2的幂次方(因为计算机和内核喜欢它们)
  • 不要太大(比如适合处理器内部某些缓存,如L2缓存)
  • 在内存中对齐(例如使用posix_memalign对齐到页面大小)。

所以16k字节到几兆字节之间的2的幂次方可能最合适。大多数时间都花在读取磁盘上。文件系统和磁盘基准测试在这个范围内相当平坦。

4k字节似乎经常是页面大小和磁盘块大小。

当然,您可以调整一些东西,甚至可以通过使用mke2fs制作文件系统时调整文件系统块大小。

我敢打赌,最优解实际上取决于您的硬件(SSD、硬盘?)和您的系统(及其负载)。


0
包含 stdio.h 应该将 BUFSIZ 定义为系统的最佳大小。这并不是绝对保证,但如果您没有能力进行广泛的基准测试,则这是要使用的正确值,并且对于这样的基准测试来说,它是一个很好的起点。

2
我认为在<stdio.h>头文件中定义的BUFSIZ与提供的FILE抽象有关。原帖作者谈论的是Linux上的write(2)系统调用,没有使用FILE抽象。我不明白为什么BUFSIZ会与此相关。 - Basile Starynkevitch
2
据我所知,BUFSIZ是传递给setvbuf的缓冲区大小。 FILE抽象旨在进行高效的IO操作,并且通常会考虑到缓冲区大小。 - William Pursell
同意,但为什么 setvbuf 的大小应该与写入的大小相同呢? - Basile Starynkevitch
1
由于缓冲区大小的选择是为了最大化缓冲效率。 - William Pursell
我认为BUFSIZ由于二进制兼容性原因并没有发生太多变化。我猜测BUFSIZ是在十多年前选择的,在那时候系统的限制和最优条件与我们当前的机器不同。 - Basile Starynkevitch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接