簡體   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