30

可能重复:
使用 FileInputStream 时如何确定理想的缓冲区大小?

当使用 C++istream系列read()或 C从文件(或任何输入流)读取原始数据时fread(),必须提供缓冲区,以及要读取的数据量。我见过的大多数程序似乎都是在 512 和 4096 之间任意选择 2 的幂。

  1. 是否有理由必须/应该是 2 的幂,或者这只是程序员对 2 的幂的自然倾向?
  2. “理想”的数字是多少?“理想”是指它是最快的。我认为它必须是底层设备缓冲区大小的倍数?或者可能是底层流对象的缓冲区?无论如何,我将如何确定这些缓冲区的大小?一旦我这样做了,使用它的倍数会比仅使用确切的大小来提高速度吗?

编辑
大多数答案似乎是在编译时无法确定。我可以在运行时找到它。

4

6 回答 6

22

SOURCE:
在使用 FileInputStream 时,您如何确定理想的缓冲区大小?

最佳缓冲区大小与许多因素有关:文件系统块大小、CPU 缓存大小和缓存延迟。

大多数文件系统配置为使用 4096 或 8192 的块大小。理论上,如果您配置缓冲区大小以便读取比磁盘块多几个字节,则对文件系统的操作可能非常低效(即,如果您将缓冲区配置为一次读取 4100 个字节,每次读取需要文件系统读取 2 次块)。如果这些块已经在缓存中,那么您最终会付出 RAM -> L3/L2 缓存延迟的代价。如果你不走运并且块还没有在缓存中,那么你也要付出磁盘-> RAM 延迟的代价。

这就是为什么您会看到大多数缓冲区大小为 2 的幂,并且通常大于(或等于)磁盘块大小。这意味着您的一个流读取可能会导致多个磁盘块读取 - 但这些读取将始终使用完整块 - 不会浪费读取。

确保这一点通常还会导致影响读取和后续处理的其他性能友好参数:数据总线宽度对齐、DMA 对齐、内存高速缓存行对齐、虚拟内存页面的整数。

于 2012-05-22T08:29:42.300 回答
4
  1. 至少在我的情况下,假设底层系统正在使用大小也是 2 的幂的缓冲区,所以最好尝试匹配。我认为现在的缓冲区应该比“大多数”程序员倾向于制作的缓冲区大一点。例如,我会选择 32 KB 而不是 4 KB。
  2. 不幸的是,很难提前知道。例如,这取决于您的应用程序是受 I/O 限制还是受 CPU 限制。
于 2012-05-22T08:29:45.640 回答
1
  1. 我认为主要是选择一个“整数”。如果计算机以十进制工作,我们可能会选择 1000 或 10000 而不是 1024 或 8192。没有很好的理由。

一个可能的原因是磁盘扇区的大小通常为 512 字节,因此读取其中的倍数会更有效,假设所有硬件层和缓存导致低级代码实际上能够有效地使用这一事实。除非您正在编写设备驱动程序或进行无缓冲读取,否则它可能无法做到。

于 2012-05-22T08:30:53.933 回答
0

我没有理由知道它必须是二的幂。您受到缓冲区大小必须在 max 范围内的限制,size_t但这不太可能成为问题。

显然,缓冲区越大越好,但这显然不可扩展,因此必须在编译时或最好在运行时考虑系统资源。

于 2012-05-22T08:33:03.230 回答
0

1. 是否有理由必须/应该是 2 的幂,或者这只是程序员对 2 的幂的自然倾向?

并不真地。它可能应该是数据总线宽度的大小以简化内存复制,因此任何划分为 16 的东西在当前技术下都会很好。使用 2 的幂使其很可能适用于任何未来的技术。

2. “理想”的数字是多少?“理想”是指它是最快的。

最快的应该是尽可能的。但是,一旦超过几千字节,与您使用的内存量相比,您的性能差异将非常小。

我认为它必须是底层设备缓冲区大小的倍数?或者可能是底层流对象的缓冲区?无论如何,我将如何确定这些缓冲区的大小?

您无法真正知道底层缓冲区的大小,或者依赖于它们保持不变。

一旦我这样做了,使用它的倍数会比仅使用确切的大小来提高速度吗?

有些,但很少。

于 2012-05-22T08:36:38.697 回答
0

我认为缓冲区的理想大小是硬盘驱动器中一个块的大小,因此它可以在存储或从硬盘驱动器获取数据时与缓冲区正确映射。

于 2012-05-22T12:15:20.703 回答