最佳文件输出缓冲区大小是多少?
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,但读取或写入将是连续的(在理想情况下)。
例如,请参见下面的代码。 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,但读取或写入将是连续的(在理想情况下)。