为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕神8447489 2019-07-26 15:14:00
当使用FileInputStream时,如何确定理想的缓冲区大小?我有一个从文件创建MessageDigest(散列)的方法,我需要对很多文件(>=100,000)这样做。我应该使用多大的缓冲区从文件中读取以最大限度地提高性能?大多数人都熟悉基本代码(我将在这里重复一遍,以防万一):MessageDigest md = MessageDigest.getInstance( "SHA" );FileInputStream ios = new FileInputStream( "myfile.bmp" );byte[] buffer = new byte[4 * 1024]; // what should this value be?int read = 0;while( ( read = ios.read( buffer ) ) > 0 )     md.update( buffer, 0, read );ios.close();md.digest();最大吞吐量缓冲区的理想大小是多少?我知道这与系统有关,我很确定它的操作系统,文件系统,和硬盘依赖,也许还有其他硬件/软件的混合。(我应该指出,我对Java有点陌生,所以这可能只是一些我不知道的JavaAPI调用。)
查看完整描述

3 回答

?
紫衣仙女

TA贡献1839条经验 获得超15个赞

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

大多数文件系统配置为使用4096或8192的块大小。理论上,如果您配置了缓冲区大小,以便比磁盘块多读几个字节,那么对文件系统的操作可能效率极低(也就是说,如果您将缓冲区配置为一次读取4100字节,则每次读取都需要由文件系统读取2个块)。如果块已经在缓存中,那么您将付出RAM->L3/L2缓存延迟的代价。如果您运气不好,而且块还没有在缓存中,那么您也要支付磁盘->RAM延迟的代价。

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

现在,在一个典型的流场景中,这被抵消了很大一部分,因为当您进入下一次读取时,从磁盘读取的块仍将在内存中(毕竟,我们在这里进行顺序读取)-所以您在下一次读取时最终支付的是RAM->L3/L2缓存延迟价格,而不是磁盘->RAM延迟。就大小而言,磁盘->RAM延迟太慢,几乎淹没了您可能处理的任何其他延迟。

因此,我怀疑如果您运行了一个具有不同缓存大小的测试(还没有亲自这么做),您可能会发现缓存大小会对文件系统块的大小产生很大的影响。除此之外,我怀疑事情会很快稳定下来。

有一个这里的情况和例外-系统的复杂性实际上是相当惊人的(仅仅得到一个处理L3->L2缓存传输是令人难以置信的复杂,它改变了每一种CPU类型)。

这就引出了“现实世界”的答案:如果你的应用程序是99%,设置缓存大小为8192并继续前进(更好的是,选择封装而不是性能,并使用BufferedInputStream隐藏细节)。如果您所处的应用程序中的1%高度依赖磁盘吞吐量,那么就可以完成您的实现,这样您就可以交换不同的磁盘交互策略,并提供旋钮和拨号,让用户能够测试和优化(或者想出一些自我优化的系统)。


查看完整回答
反对 回复 2019-07-27
?
喵喔喔

TA贡献1735条经验 获得超5个赞

是的,它可能取决于各种事情-但我怀疑它会有很大的区别。我倾向于选择16K或32K作为内存使用和性能之间的良好平衡。

请注意,在代码中应该有一个try/Finish块,以确保即使抛出异常也关闭流。


查看完整回答
反对 回复 2019-07-27
?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

在大多数情况下,这并不重要。只要选择一个好的大小,如4K或16K,并坚持它。如果你阳性这是应用程序中的瓶颈,那么您应该开始分析以找到最佳的缓冲区大小。如果您选择的大小太小,则会浪费时间进行额外的I/O操作和额外的函数调用。如果您选择一个太大的大小,您将开始看到许多缓存缺失,这将真正减慢您的速度。不要使用大于L2缓存大小的缓冲区。

查看完整回答
反对 回复 2019-07-27
  • 3 回答
  • 0 关注
  • 322 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号