簡體   English   中英

Java性能 - 如何將大數組寫入具有高性能的磁盤/ SD卡?

[英]Java Performance - How to write big array to disk/sdcard with high performance?

有沒有辦法在Java中向磁盤寫入一大堆,比如整數? 我在Android上這樣做,並沒有找到任何接近本機C代碼的方法。

生成的文件不需要可移植到具有不同表示的不同機器,因此邏輯上只是對底層字節的批量寫入就足夠了。 但我不知道如何從Java有效地做到這一點。

我試過在網上搜索,並測試了以下內容:

  • 序列化 - 非常慢,正如預期的那樣。
  • 使用NIO - 仍然很慢 - Android跟蹤每個整數一次顯示一個操作:

提前致謝


NIO代碼:

int[] array = new array[10000000];

...

raf = new RandomAccessFile(ti.testFileName, "rw");
chan = raf.getChannel();
MappedByteBuffer out = chan.map(FileChannel.MapMode.READ_WRITE, 0, array.length*4);
ib = out.asIntBuffer();
ib.put(array);
out.force();
raf.close();

你說它很慢但速度很可能取決於磁盤子系統的速度。 您應該能夠在大約半秒內將40 MB寫入常規磁盤以提交到磁盤。

以下使用NIO,在工作站上寫入需要665 ms,在工作站上需要62 ms。 讀取和寫入會使相同數量的數據混亂,但讀取可以從OS緩存中獲取數據,這與寫入磁盤所需的時間不同。

int[] ints = new int[10 * 1000 * 1000];
long start = System.nanoTime();

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(ints.length*4+4);
byteBuffer.putInt(ints.length);
IntBuffer intBuffer = byteBuffer.asIntBuffer();
intBuffer.put(ints);
byteBuffer.position(0);

FileChannel fc = new FileOutputStream("main.dat").getChannel();
fc.write(byteBuffer);
fc.force(false);
fc.close();
long time = System.nanoTime() - start;
System.out.println("Write time " + time / 1000 / 1000 + " ms.");

long start2 = System.nanoTime();
FileChannel fc2 = new FileInputStream("main.dat").getChannel();
ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
while(lengthBuffer.remaining()>0) fc2.read(lengthBuffer);
int length = lengthBuffer.getInt(0);

int[] ints2 = new int[length];
ByteBuffer buffer2 = ByteBuffer.allocateDirect(length*4);
while(buffer2.remaining()>0 && fc2.read(buffer2) > 0);
buffer2.flip();
buffer2.asIntBuffer().get(ints2);
long time2 = System.nanoTime() - start2;
System.out.println("Read time " + time2 / 1000 / 1000 + " ms.");

我已將長度添加到文件的開頭,因此不必假設它。 順便說一下:我修復了寫中的錯誤。

我不知道Android實現,但在標准Java中,良好的老式IO通常優於NIO。

例如,如果你有一個字節數組,我相信下面的代碼應該相對較快:

byte[] bytes = new byte[10000];
// ...
FileOutputStream out = new FileOutputStream(...);
try {
    out.write(bytes);
} finally {
    out.close();
}

請記住,這將阻塞,直到寫入整個字節數組。 但是你沒有說明非阻塞行為是否存在問題。

你沒有提到的另一件事是你打算在寫入文件時如何編碼整數。 您需要在寫入文件之前在內存中執行編碼,但是數組可能太大而無法一次編碼所有內容,在這種情況下,您可以使用幾百K的塊進行編碼/寫入。

彼得,

當事情看起來好得令人難以置信時,通常情況就是如此。 寫入40MB數據的89msecs表明你的硬盤帶寬要大得多500MB /秒(因為你還包括打開和關閉文件的時間)。 這不可能是真的。 你檢查的文件實際上是40MB大小。 另外,我建議您初始化緩沖區以查看文件內容不是全部為零。 可能是一個未被觸及的緩沖區,只是跳過了。 不管它是什么,你擁有的數字太好了,不可能成真。

謝謝。

考慮一下緩沖輸出流

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM