繁体   English   中英

为什么RandomAccessFile writeLong用多次写调用实现?

[英]Why is RandomAccessFile writeLong implemented with multiple write calls?

在分析应用程序时,我注意到RandomAccessFile.writeLong花了很多时间。

我检查了这个方法的代码,它涉及8次本机方法写入调用。 我使用byte []为writeLong编写了一个替代实现。 像这样的东西:

RandomAccessFile randomAccessFile = new RandomAccessFile("out.dat", "rwd");
...
byte[] aux = new byte[8];
aux[0] = (byte) ((l >>> 56) & 0xFF);
aux[1] = (byte) ((l >>> 48) & 0xFF);
aux[2] = (byte) ((l >>> 40) & 0xFF);
aux[3] = (byte) ((l >>> 32) & 0xFF);
aux[4] = (byte) ((l >>> 24) & 0xFF);
aux[5] = (byte) ((l >>> 16) & 0xFF);
aux[6] = (byte) ((l >>> 8) & 0xFF);
aux[7] = (byte) ((l >>> 0) & 0xFF);
randomAccessFile.write(aux);

我做了一个小基准测试并得到了这些结果:

使用writeLong():
平均调用时间:91毫秒

使用write(byte []):
平均调用时间:11毫秒

在具有Intel(R)CPU T2300 @ 1.66GHz的Linux机器上进行测试

由于本机调用会有一些性能损失,为什么writeLong会以这种方式实现? 我知道应该向太阳队员提出这个问题,但我希望这里的人有一些提示。

谢谢。

RandomAccessFile.writeLong()似乎不会最小化对OS的调用次数。 通过使用“rwd”而不是“rw”来显着增加成本,这应该足以表明它本身不需要花费时间。 (事实上​​,操作系统试图将每次写入提交到磁盘,并且磁盘只会旋转得太快)

{
    RandomAccessFile raf = new RandomAccessFile("test.dat", "rwd");
    int longCount = 10000;
    long start = System.nanoTime();
    for (long l = 0; l < longCount; l++)
        raf.writeLong(l);
    long time = System.nanoTime() - start;
    System.out.printf("writeLong() took %,d us on average%n", time / longCount / 1000);
    raf.close();
}
{
    RandomAccessFile raf = new RandomAccessFile("test2.dat", "rwd");
    int longCount = 10000;
    long start = System.nanoTime();
    byte[] aux = new byte[8];
    for (long l = 0; l < longCount; l++) {
        aux[0] = (byte) (l >>> 56);
        aux[1] = (byte) (l >>> 48);
        aux[2] = (byte) (l >>> 40);
        aux[3] = (byte) (l >>> 32);
        aux[4] = (byte) (l >>> 24);
        aux[5] = (byte) (l >>> 16);
        aux[6] = (byte) (l >>> 8);
        aux[7] = (byte) l;
        raf.write(aux);
    }
    long time = System.nanoTime() - start;
    System.out.printf("write byte[8] took %,d us on average%n", time / longCount / 1000);
    raf.close();
}

版画

writeLong() took 2,321 us on average
write byte[8] took 576 us on average

在我看来,你没有磁盘写缓存。 没有磁盘缓存,我希望每个提交的写入对于5400 RPM磁盘大约需要11毫秒,即60000毫秒/ 5400 => 11毫秒。

我会投票反对懒惰,或者(更加慈善)不考虑后果。

writeLong()本机实现可能需要每个体系结构的版本,以处理字节排序(JNI将转换为平台字节顺序)。 通过将转换保持在“跨平台”层,开发人员简化了移植工作。

至于为什么他们在Java端没有转换为数组,我怀疑这是因为害怕垃圾收集。 我猜想RandomAccessFile自1.1以来已经发生了微小的变化,直到1.3,垃圾收集才开始使小对象分配“免费”。

但是 ,还有RandomAccessFile的替代方案:看看MappedByteBuffer


编辑:我有一台JDK 1.2.2的机器,从那时起这个方法没有改变。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM