Durante l'elaborazione di più file gigabyte ho notato qualcosa di strano: sembra che la lettura da un file utilizzando un file-channel in un oggetto ByteBuffer riutilizzato allocato con allocateDirect sia molto più lenta della lettura da un MappedByteBuffer, infatti è anche più lento della lettura in array di byte usando normali chiamate di lettura!Java Prestazioni prestazioni buffer Byte
mi aspettavo di essere (quasi) più veloce la lettura da mappedbytebuffers come il mio ByteBuffer viene allocata con allocateDirect, da qui la lettura dovrebbe finire-up direttamente nel mio ByteBuffer senza copie intermedie.
La mia domanda ora è: che cosa sto facendo di sbagliato? O il bytebuffer + filechannel è davvero lento rispetto al normale io/mmap?
I il codice di esempio seguente ho aggiunto anche del codice che converte ciò che viene letto in valori lunghi, poiché questo è ciò che il mio codice reale fa costantemente. Mi aspetto che il metodo ByteBuffer getLong() sia molto più veloce del mio byte shuffeler.
Test-risultati: mmap: 3.828 ByteBuffer: 55,097 regolari I/O: 38,175
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.MappedByteBuffer;
class testbb {
static final int size = 536870904, n = size/24;
static public long byteArrayToLong(byte [] in, int offset) {
return ((((((((long)(in[offset + 0] & 0xff) << 8) | (long)(in[offset + 1] & 0xff)) << 8 | (long)(in[offset + 2] & 0xff)) << 8 | (long)(in[offset + 3] & 0xff)) << 8 | (long)(in[offset + 4] & 0xff)) << 8 | (long)(in[offset + 5] & 0xff)) << 8 | (long)(in[offset + 6] & 0xff)) << 8 | (long)(in[offset + 7] & 0xff);
}
public static void main(String [] args) throws IOException {
long start;
RandomAccessFile fileHandle;
FileChannel fileChannel;
// create file
fileHandle = new RandomAccessFile("file.dat", "rw");
byte [] buffer = new byte[24];
for(int index=0; index<n; index++)
fileHandle.write(buffer);
fileChannel = fileHandle.getChannel();
// mmap()
MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, size);
byte [] buffer1 = new byte[24];
start = System.currentTimeMillis();
for(int index=0; index<n; index++) {
mbb.position(index * 24);
mbb.get(buffer1, 0, 24);
long dummy1 = byteArrayToLong(buffer1, 0);
long dummy2 = byteArrayToLong(buffer1, 8);
long dummy3 = byteArrayToLong(buffer1, 16);
}
System.out.println("mmap: " + (System.currentTimeMillis() - start)/1000.0);
// bytebuffer
ByteBuffer buffer2 = ByteBuffer.allocateDirect(24);
start = System.currentTimeMillis();
for(int index=0; index<n; index++) {
buffer2.rewind();
fileChannel.read(buffer2, index * 24);
buffer2.rewind(); // need to rewind it to be able to use it
long dummy1 = buffer2.getLong();
long dummy2 = buffer2.getLong();
long dummy3 = buffer2.getLong();
}
System.out.println("bytebuffer: " + (System.currentTimeMillis() - start)/1000.0);
// regular i/o
byte [] buffer3 = new byte[24];
start = System.currentTimeMillis();
for(int index=0; index<n; index++) {
fileHandle.seek(index * 24);
fileHandle.read(buffer3);
long dummy1 = byteArrayToLong(buffer1, 0);
long dummy2 = byteArrayToLong(buffer1, 8);
long dummy3 = byteArrayToLong(buffer1, 16);
}
System.out.println("regular i/o: " + (System.currentTimeMillis() - start)/1000.0);
}
}
Come caricare grandi sezioni e poi di elaborazione è di loro non è un'opzione (io sto leggendo i dati dappertutto) Penso che dovrei attenermi a un MappedByteBuffer. Grazie a tutti per i vostri suggerimenti.
Questo sarebbe davvero più veloce. Non mi aspettavo che fosse molto più veloce, quindi grazie! –
Se non sbaglio, la sezione I/O regolare intende utilizzare buffer3 in entrambi i cicli, piuttosto che leggere i lunghi fuori dal buffer1 invariato. –