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

我正在阅读二进制文件,这里是一个示例:

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等)以及其上存在的分区的分段大小(我们可以在格式化分区时定义)。

但是这里有一个问题: 是否有任何公式或最佳实践来定义缓冲区大小? 现在,我正在基于反复试验来定义。

编辑:我testing了我的服务器上的应用程序与不同的缓冲区大小,我得到了4095 * 256 * 16(16 MB)的最佳性能! 4096慢了4秒。

这里有一些旧post是非常有帮助的,但我仍然不能得到原因:

  • .NET中更快(不安全)的BinaryReader

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

  • 文件I / O与stream – 最佳的内存缓冲区大小

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

“ 顺序文件编程模式和与.NET性能 ”是I / O性能改进的一个伟大的文章。

在该 PDF文件的第8页,显示了大于八字节的缓冲区大小的带宽是恒定的。 考虑到这篇文章是在2004年撰写的,硬盘是“ 迈拓250 GB 7200 RPM SATA磁盘 ”,结果应该与最新的I / O技术有所不同。

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

在未缓冲的I / O中,磁盘数据直接在应用程序的地址空间和设备之间移动,无需任何中间复制。

概要

  • 对于单个磁盘,使用.NET框架的默认值 – 它们为顺序文件访问提供了出色的性能。
  • 在创建文件时,预先分配大量顺序文件(使用SetLength()方法)。 与碎片文件相比,这通常可将速度提高约13%。
  • 至少现在,磁盘阵列需要非缓冲I / O才能达到最高性能 – 缓冲I / O比未缓冲I / O要慢八倍。 我们预计这个问题将在.NET框架的后续版本中解决。
  • 如果你做自己的缓冲,使用大的请求大小(64 KB是一个很好的开始)。 使用.NET框架,单个处理器可以使用未缓冲的I / O以超过800 Mbytes / s的速度读取和写入磁盘阵列。

没有最好最差的缓冲区大小,但你必须看一些方面。

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

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