缓冲输出流比Java中的输入流更有效吗?

pmc*_*mcs 10 java stream

今天早些时候感到无聊,我开始考虑Java中缓冲和无缓冲字节流的相对性能.作为一个简单的测试,我下载了一个相当大的文本文件并编写了一个简短的程序来确定缓冲流在复制文件时的效果.进行了四项测试:

  1. 使用无缓冲的输入和输出字节流复制文件.
  2. 使用缓冲的输入流和无缓冲的输出流复制文件.
  3. 使用无缓冲的输入流和缓冲的输出流复制文件.
  4. 使用缓冲的输入和输出流复制文件.

不出所料,使用缓冲的输入和输出流比使用无缓冲的流快几个数量级.然而,真正有趣的事情(至少对我来说)是案例2和3之间的速度差异.一些样本结果如下:

Unbuffered input, unbuffered output
Time: 36.602513585

Buffered input, unbuffered output
Time: 26.449306847

Unbuffered input, buffered output
Time: 6.673194184

Buffered input, buffered output
Time: 0.069888689
Run Code Online (Sandbox Code Playgroud)

对于那些感兴趣的人,代码可以在Github上找到.任何人都可以解释为什么案例2和案例3的时间如此不对称?

Mar*_*ers 10

当您读取文件时,它下面的文件系统和设备会执行各种级别的缓存.他们几乎从不读过一个字节; 他们看了一块.在随后读取下一个字节时,该块将位于缓存中,因此速度会快得多.

因此,如果您的缓冲区大小与块大小相同,那么缓冲输入流实际上并没有获得那么多(它节省了一些系统调用,但就实际物理I/O而言)不会为你节省太多钱).

当你编写一个文件时,文件系统无法为你缓存,因为你没有给它写积压的东西.它可能会为您缓冲输出,但它必须对刷新缓冲区的频率做出有根据的猜测.通过自己缓冲输出,您可以让设备一次完成更多工作,因为您手动构建了积压工作.

  • "当你编写一个文件时,文件系统无法缓存"不完全:Linux(以及我使用过的所有其他"真正的"操作系统,包括最新版本的Windows)都会保留一个要写入的脏页缓存到磁盘(这就是为什么`sync`存在). (3认同)