最佳文件输出缓冲区大小是多少?

What is the optimal file output buffer size?

例如,请参见下面的代码。 size是1MB,肯定比1的时候快运行s。我想是IO系统调用次数减少的缘故。这是否意味着我将始终受益于更大的缓冲区大小?我希望如此 运行 一些测试,但似乎有一些限制。 size 为 2 时 运行 比为 1 时要快得多,但不会更进一步。

有人能更好地解释一下吗?最佳缓冲区大小可能是多少?为什么我不能从无限扩大它的规模中获益良多。

顺便说一句,在这个例子中,为了简单起见,我写到stdout,但我也在考虑写入磁盘中文件的时间。

enum
{
  size = 1 << 20
};

void fill_buffer(char (*)[size]);

int main(void)
{
  long n = 100000000;
  for (;;)
  {
    char buf[size];
    fill_buffer(&buf);
    if (n <= size)
    {
      if (fwrite(buf, 1, n, stdout) != n)
      {
        goto error;
      }
      break;
    }
    if (fwrite(buf, 1, size, stdout) != size)
    {
      goto error;
    }
    n -= size;
  }
  return EXIT_SUCCESS;
error:
  fprintf(stderr, "fwrite failed\n");
  return EXIT_FAILURE;
}

您通常不需要 最佳 缓冲区大小,这可能需要查询 OS 系统参数并对目标环境进行复杂的估计甚至基准测试,而且是动态的。幸运的是,您只需要一个 足够好 .

的值

我会说 4K~16K 缓冲区适合大多数正常使用。其中 4K 是普通机器(x86,arm)支持的页面大小的幻数,也是通常物理磁盘扇区大小(512B 或 4K)的倍数。

如果您正在处理大量数据(千兆字节),您可能会意识到简单的 fwrite-model 不足以满足其阻塞特性。

在大分区上,簇大小通常为 32 KB。在一个大的读/写请求上,如果系统看到有一系列连续的簇,它会将它们组合成一个 I/O。否则,它将请求分解为多个 I/O。我不知道最大 I/O 大小是多少。在一些旧的 SCSI 控制器上,它是 64 KB 或 1 MB - 8 KB(17 或 255 个描述符,在控制器中)。对于 IDE / Sata,我已经能够为 2 MB 执行 IOCTL,确认它是一个带有外部总线监视器的单个 I/O,但我从未测试过以确定限制。

对于 k > 2 的 k 路自下而上合并排序的外部排序,使用 10 MB 到 100 MB 的读/写大小来减少随机访问开销。该请求将被分解为多个 I/O,但读取或写入将是连续的(在理想情况下)。