使用 BinaryReader 读取大文件 (>1 GB) 时的最佳缓冲区大小是多少

本文关键字:最佳 缓冲区 多少 GB 读取 BinaryReader 文件 使用 | 更新日期: 2023-09-27 18:36:36

我正在读取二进制文件,下面是一个示例:

public static byte[] ReadFully(Stream input)
{
    byte[] buffer = new byte[16*1024];
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        ......
    }
}

显然,缓冲区大小(16*1024)对性能有很大影响。我读过它取决于I/O技术(SATA,SSD,SCSI等)以及存在于其上的分区的片段大小(我们可以在格式化分区期间定义)。

但问题是:是否有任何公式或最佳实践来定义缓冲区大小?现在,我正在根据试错进行定义。

编辑:我已经使用不同的缓冲区大小在服务器上测试了该应用程序,并以 4095*256*16 (16 MB) 获得最佳性能!!4096 慢 4 秒。

以下是一些非常有用的旧帖子,但我仍然无法理解原因:

  • .NET 中更快(不安全)的二进制读取器

  • 最佳文件缓冲区读取大小?

  • 带流的文件 I/O - 最佳内存缓冲区大小

  • 使用FileInputStream时如何确定理想的缓冲区大小?

使用 BinaryReader 读取大文件 (>1 GB) 时的最佳缓冲区大小是多少

"使用

.NET 的顺序文件编程模式和性能"是 I/O 性能改进方面的一篇很棒的文章。

在此 PDF 文件的第 8 页中,它显示缓冲区大小大于 8 个字节的带宽是恒定的。考虑到这篇文章写于 2004 年,硬盘驱动器是"迈拓 250 GB 7200 RPM SATA 磁盘",结果应该与最新的 I/O 技术不同。

如果您正在寻找最佳性能,请查看 PDF 文件的 pinvoke.net 或第 9 页,未缓冲的文件性能测量结果会显示出更好的结果:

在非缓冲 I/O 中,磁盘数据直接在 应用程序的地址空间和设备,没有任何中间 复制。

总结

  • 对于单个磁盘,请使用 .NET 框架的默认值 - 它们为顺序文件访问提供了出色的性能。
  • 在创建文件时预先分配大型顺序文件(使用 SetLength() 方法)。与碎片文件相比,这通常会将速度提高约 13%。
  • 至少就目前而言,磁盘阵列需要无缓冲 I/O 才能实现最高性能 - 缓冲 I/O 可能比无缓冲 I/O 慢八倍。我们希望此问题将在 .NET 框架的更高版本中得到解决。
  • 如果您自己进行缓冲,请使用较大的请求大小(64 KB 是一个很好的起点)。使用 .NET 框架,单个处理器可以使用非缓冲 I/O 以超过 800 MB/s 的速度读取和写入磁盘阵列。

没有最佳最差缓冲区大小,但您必须查看某些方面。

由于您使用的是 C#,因此您在 Windows 上运行,因此 Windows 使用 NTFS,其页面大小为 4 MB,因此建议使用 4096 的倍数。所以你的缓冲区大小是 16*1024 = 4*4096 ,这是一个不错的选择,但要说它比16*4096更好还是更差,我们不能说。

一切都取决于情况和程序的要求。请记住,在这里您不能选择最佳选项,而只能选择更好的选项。我建议使用 4096 ,但您也可以使用自己的4*4096甚至16*4096,但请记住,此缓冲区将分配给堆上,因此它的分配需要一些时间,因此您不想分配一个大的缓冲区,例如128*4096