2011-04-21 34 views
5

在分析应用程序时,我注意到RandomAccessFile.writeLong花了很多时间。为什么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毫秒

使用写入(字节[ ]):
平均调用时间:11 ms

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

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

谢谢。

回答

2

我会投赞成懒惰,或者(更慈善)不考虑后果。

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

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

,有以RandomAccessFile一种替代方案:看看MappedByteBuffer


编辑:我有一台机器与JDK 1.2.2,而这种方法自那时以来一直没有改变。

2

看起来,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 

这样看来,我认为你有没有磁盘写入缓存。如果没有磁盘高速缓存,我期望每个提交的写入大约需要11毫秒的5400 RPM磁盘,即60000毫秒/ 5400 => 11毫秒。

+0

是的,这是毫秒。 – jassuncao 2011-04-21 10:25:31

+0

它们应该快得多。你可以试试我的测试代码是微秒吗? – 2011-04-21 10:27:11

+0

在我的测试中,我也使用'd'标志。这使写入同步,使写入慢很多。 – jassuncao 2011-04-21 10:42:29

相关问题