ストリームIO,NIO,メモリマップ読み込み速度テスト簡単分析
21509 ワード
テスト環境
cpu: intel® core™ i 7-8750 Hメモリ:16 Gハードディスク:512 SSDテストファイル:四つのファイルのzipパッケージ、圧縮後のサイズ1.73 GB
テスト結果
フローIO読み出しサンプルコード
final int BUFFER_SIZE = 1024;
int i = 0;
byte[] bytes = new byte[BUFFER_SIZE];
File file2 = new File(filePath);
FileInputStream in2 = new FileInputStream(file2);
long begin3 = System.currentTimeMillis();
while (in2.read(bytes) > 0){
i++;
}
in2.close();
long end3 = System.currentTimeMillis();
System.out.println("count is:" + i);
System.out.println("time is:" + (end3 - begin3));
NIO読み出しサンプルコード
final int BUFFER_SIZE = 1024;
int i = 0;
File file = new File(filePath);
FileInputStream in = new FileInputStream(file);
FileChannel channel2 = in.getChannel();
ByteBuffer buff = ByteBuffer.allocate(BUFFER_SIZE);
long begin2 = System.currentTimeMillis();
while (channel2.read(buff) != -1) {
i++;
buff.flip();
buff.clear();
}
channel2.close();
long end2 = System.currentTimeMillis();
System.out.println("count is:" + i);
System.out.println("time is:" + (end2 - begin2));
メモリマッピング読み込みサンプルコード
final int BUFFER_SIZE = 1024;
int i = 0;
byte[] bytes = new byte[BUFFER_SIZE];
RandomAccessFile memoryMappedFile = new RandomAccessFile(filePath, "rw");
FileChannel channel = memoryMappedFile.getChannel();
final long len = channel.size();
long begin = System.currentTimeMillis();
MappedByteBuffer out = channel.map(FileChannel.MapMode.READ_WRITE, 0, len);
for (int offset = 0; offset < len; offset += BUFFER_SIZE) {
i++;
if (len - offset >= BUFFER_SIZE) {
out.get(bytes);
} else {
out.get(bytes,0,(int) len - offset);
}
}
memoryMappedFile.close();
long end = System.currentTimeMillis();
System.out.println("count is:" + i);
System.out.println("time is: " + (end - begin));
テスト結果
それぞれのテストバッファは1 K,1 M,10 Mである.ケースごとに3回実行
buffer size
フローIO
NIO
メモリマッピング
1K
count is:1818681 time is:4717
count is:1818681 time is:4873
count is:1818681 time is:736
1K
count is:1818681 time is:4673
count is:1818681 time is:4779
count is:1818681 time is:733
1K
count is:1818681 time is:4700
count is:1818681 time is:4731
count is:1818681 time is:728
1M
count is:1777 time is:1139
count is:1777 time is:459
count is:1777 time is:757
1M
count is:1777 time is:1148
count is:1777 time is:454
count is:1777 time is:744
1M
count is:1777 time is:1103
count is:1777 time is:461
count is:1777 time is:764
10M
count is:178 time is:1293
count is:178 time is:964
count is:178 time is:830
10M
count is:178 time is:1263
count is:178 time is:903
count is:178 time is:845
10M
count is:178 time is:1241
count is:178 time is:896
count is:178 time is:840
結論
フローIO読み出しサンプルコード
final int BUFFER_SIZE = 1024;
int i = 0;
byte[] bytes = new byte[BUFFER_SIZE];
File file2 = new File(filePath);
FileInputStream in2 = new FileInputStream(file2);
long begin3 = System.currentTimeMillis();
while (in2.read(bytes) > 0){
i++;
}
in2.close();
long end3 = System.currentTimeMillis();
System.out.println("count is:" + i);
System.out.println("time is:" + (end3 - begin3));
NIO読み出しサンプルコード
final int BUFFER_SIZE = 1024;
int i = 0;
File file = new File(filePath);
FileInputStream in = new FileInputStream(file);
FileChannel channel2 = in.getChannel();
ByteBuffer buff = ByteBuffer.allocate(BUFFER_SIZE);
long begin2 = System.currentTimeMillis();
while (channel2.read(buff) != -1) {
i++;
buff.flip();
buff.clear();
}
channel2.close();
long end2 = System.currentTimeMillis();
System.out.println("count is:" + i);
System.out.println("time is:" + (end2 - begin2));
メモリマッピング読み込みサンプルコード
final int BUFFER_SIZE = 1024;
int i = 0;
byte[] bytes = new byte[BUFFER_SIZE];
RandomAccessFile memoryMappedFile = new RandomAccessFile(filePath, "rw");
FileChannel channel = memoryMappedFile.getChannel();
final long len = channel.size();
long begin = System.currentTimeMillis();
MappedByteBuffer out = channel.map(FileChannel.MapMode.READ_WRITE, 0, len);
for (int offset = 0; offset < len; offset += BUFFER_SIZE) {
i++;
if (len - offset >= BUFFER_SIZE) {
out.get(bytes);
} else {
out.get(bytes,0,(int) len - offset);
}
}
memoryMappedFile.close();
long end = System.currentTimeMillis();
System.out.println("count is:" + i);
System.out.println("time is: " + (end - begin));
テスト結果
それぞれのテストバッファは1 K,1 M,10 Mである.ケースごとに3回実行
buffer size
フローIO
NIO
メモリマッピング
1K
count is:1818681 time is:4717
count is:1818681 time is:4873
count is:1818681 time is:736
1K
count is:1818681 time is:4673
count is:1818681 time is:4779
count is:1818681 time is:733
1K
count is:1818681 time is:4700
count is:1818681 time is:4731
count is:1818681 time is:728
1M
count is:1777 time is:1139
count is:1777 time is:459
count is:1777 time is:757
1M
count is:1777 time is:1148
count is:1777 time is:454
count is:1777 time is:744
1M
count is:1777 time is:1103
count is:1777 time is:461
count is:1777 time is:764
10M
count is:178 time is:1293
count is:178 time is:964
count is:178 time is:830
10M
count is:178 time is:1263
count is:178 time is:903
count is:178 time is:845
10M
count is:178 time is:1241
count is:178 time is:896
count is:178 time is:840
結論
疑問
に答える
疑問に対してNIO readメソッドのコードをいくつか考えさせてください.read関数のソースコードを開くと見つかります.sun.nio.ch.IOUtil#read(java.io.FileDescriptor, java.nio.ByteBuffer, long, sun.nio.ch.NativeDispatcher)
static int read(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException {
if (var1.isReadOnly()) {
throw new IllegalArgumentException("Read-only buffer");
} else if (var1 instanceof DirectBuffer) {
return readIntoNativeBuffer(var0, var1, var2, var4);
} else {
ByteBuffer var5 = Util.getTemporaryDirectBuffer(var1.remaining());
int var7;
try {
int var6 = readIntoNativeBuffer(var0, var5, var2, var4);
var5.flip();
if (var6 > 0) {
var1.put(var5);
}
var7 = var6;
} finally {
Util.offerFirstTemporaryDirectBuffer(var5);
}
return var7;
}
}
ここから、バッファが直接メモリJDKでない場合、同じサイズの一時的な直接メモリ読み出しファイルが作成され、一時的な直接メモリからコピーされることがわかります.したがって、コードを変更するには、直接メモリをバッファとして使用して再テストします.
//
ByteBuffer buff = ByteBuffer.allocateDirect(BUFFER_SIZE);
buffer size
NIO+ダイレクトメモリ
NIO
1K
count is:1818681 time is:4720
count is:1818681 time is:4873
1K
count is:1818681 time is:4620
count is:1818681 time is:4873
1K
count is:1818681 time is:4622
count is:1818681 time is:4873
1M
count is:1777 time is:314
count is:1777 time is:454
1M
count is:1777 time is:330
count is:1777 time is:454
1M
count is:1777 time is:310
count is:1777 time is:454
10M
count is:178 time is:514
count is:178 time is:896
10M
count is:178 time is:510
count is:178 time is:896
10M
count is:178 time is:510
count is:178 time is:896
テスト結果から,直接メモリをバッファとして使用すると読み取り速度は一定に向上するが,バッファが小さい場合でも遅いのは,自身の読み取り方式の問題であるはずである.疑問2メモリマッピングでは、ファイルをメモリに完全にロードすることはできませんが、プリフェッチがメモリ間でコピーされているため、速度が速く、メモリマッピングを使用すると、カーネル領域からユーザー領域へのデータのコピーを節約するだけで、他の読み取り方法は1回だけメモリコピーが遅くなったのはなぜか説明できません.