Java New I/O part5(最終回)
New I/Oの話題はMappingByteBufferやSelectorの話もあるが、ここで一旦打ち切り。最終回は、本当にNew I/Oは今までのI/Oより速いか、測ってみた。プログラムの内容は、前回の練習問題でやったファイルの中身をすべてビット反転して、ファイルに出力するというものだ。ファイルのサイズは100MB(=10,240KB)。同じ処理を10回ループして、その処理時間を合計している。時間計測にはSystem.nanoTime()を使った。測定プログラムは次の通り。
import java.io.*; import java.nio.*; import java.nio.channels.*; import java.text.*; public class Main { public static void main(String[] args) throws Exception { if( args.length != 2 ) return; final int MAX = 10; tern1(args); tern2(args); final long start1 = System.nanoTime(); for(int i=1; i<=MAX; ++i) tern1(args); final long end1 = System.nanoTime(); final long dt1 = (end1 - start1) / 1000L; final long start2 = System.nanoTime(); for(int i=1; i<=MAX; ++i) tern2(args); final long end2 = System.nanoTime(); final long dt2 = (end2 - start2) / 1000L; final DecimalFormat fmt = new DecimalFormat("#,##0"); System.out.println("処理時間1:" + fmt.format(dt1) + "micro sec"); System.out.println("処理時間2:" + fmt.format(dt2) + "micro sec"); } public static void tern1(String[] args) throws IOException { FileInputStream in = new FileInputStream(args[0]); FileOutputStream out = new FileOutputStream(args[1]); FileChannel inch = in.getChannel(); FileChannel outch = out.getChannel(); ByteBuffer buf = ByteBuffer.allocate(1024*1024); while( inch.read(buf) != -1 ) { buf.flip(); while(buf.position() < buf.limit()) { byte b = buf.get(); buf.position(buf.position() - 1); buf.put((byte) (b ^ 0xFF)); } buf.flip(); outch.write(buf); buf.clear(); } outch.force(true); out.close(); in.close(); } public static void tern2(String[] args) throws IOException { BufferedInputStream in = new BufferedInputStream(new FileInputStream(args[0])); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(args[1])); int c; while( (c = in.read()) != -1 ) out.write((byte) (c ^ 0xFF)); out.flush(); out.close(); in.close(); } }
さて、結果は、
java.nioの場合:12.72 sec / 回 java.ioの場合: 10.43 sec / 回
…なんかjava.ioの方が速いんですけど。java.nioでByteBufferを作るとき、一気に100MB allocateしたかったのだが、OutOfMemoryErrorが出てしまったので、しかたなく1MBずつ100回ループすることにした。
もしかしたらBufferを作る時間がかかっているのかも知れない。ちなみにC++で作ったものは↓。処理時間は 7.87 sec / 回 だった。
#include <cstdio> #include <iostream> #include <windows.h> using namespace std; void tern() { FILE* in = fopen("hoge.dat", "rb"); FILE* out = fopen("piyo.dat", "wbc"); fseek(in, 0, SEEK_END); long size = ftell(in); fseek(in, 0, SEEK_SET); unsigned char* buf = new unsigned char[size]; fread(buf, 1, size, in); for(int i=0; i<size; ++i) buf[i] ^= 0xFF; fwrite(buf, 1, size, out); delete[] buf; fflush(out); fclose(out); fclose(in); } int main() { tern(); LARGE_INTEGER start, end, freq; ::QueryPerformanceFrequency(&freq); ::QueryPerformanceCounter(&start); for(int i=1; i<=10; ++i) tern(); ::QueryPerformanceCounter(&end); double dt = static_cast<double>(end.QuadPart - start.QuadPart) / freq.QuadPart; cout << dt << endl; }