2016年 2月

ファイルの読み込み速度をゴニョゴニョしてみた。

Java

今さらですが Java の入出力でファイルの読み込み速度を比較をするプログラムを組んでみた。

Java の入出力の API もバージョンが上がるごとに地味に便利になってきています。

そんなこんなでオーソドックスなスタイルからハイパフォーマンスなものまで適当にやってみました。

とりあえず、ファイルを読み込むだけ(バイト値を合計する処理)のシンプルなものとしました。

既に良く知られていることですが、FileChannel を使えば FileInputStream や BufferedInputStream を使ったオーソドックスなコードより高速に読み込めます。

今回ちょっと気になってたのが下記のものです。

java.nio.file.Files の public static byte[] readAllBytes(Path path) throws IOException です。

非常に興味深い結果を出してくれました。

実は、readAllBytes(Path path) は内部で java.nio.channels パッケージの SeekableByteChannel インタフェースを使っていました。

よって、java.nio.channels を使うのに適している大きめのファイルに対して高速に処理ができるようです。

readAllBytes

今まで使ったこと無かったから知らなかった。( ̄▽ ̄;)

しかし、API ドキュメントには「大きなファイルを読み取ることを目的とはしていません。」とあります。

ファイルが 2 ギガバイトを超えるなどした場合、OutOfMemoryError が投げられるようです。

それに「このメソッドは、すべてのバイトが読み取られたか、入出力エラーまたは他の実行時例外がスローされたときに必ずそのファイルがクローズされるようにします。」とあります。

だから大きなファイルには適さないのかもしれません。

本当はこんなにいろいろ比較するつもりじゃなかったのでいつも以上に酷いことになってます。

また、読み込み用ファイルの作成方法も「これは・・・あかんやろ・・・」ってほど非効率なものになっています。(>_<。)

それではプログラムと実行結果を貼っておきます。

約2メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp5030517990935223178.txt に作成します。
テスト用一時ファイルのサイズは、2097222 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒0018270110000000001  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒0016099900000000002  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒001935356  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒001790015  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒001790015  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒001814459  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒001435249  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒00122087  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒0017662320000000002  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒0018725950000000001  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒0010583510000000001  ———— )

テスト終了!

 

約8メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp8676206647067718269.txt に作成します。
テスト用一時ファイルのサイズは、8388627 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒00741639  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒007126697  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒0057324080000000005  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒005674932000000001  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒005462535  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒005980479  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒005093565  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒004786035  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒006010209000000001  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒005818622000000001  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒004599734  ———— )

テスト終了!

 

約16メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp4534373118077736467.txt に作成します。
テスト用一時ファイルのサイズは、16777254 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒014226638000000002  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒014306246000000002  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒010903929000000001  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒010355595  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒011318484  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒010636368  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒009792727000000001  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒009329945000000001  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒01143806  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒011517998000000002  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒010098274  ———— )

テスト終了!

 

約32メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp551612105990559011.txt に作成します。
テスト用一時ファイルのサイズは、33554508 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒030031225  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒030403168  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒022357514000000002  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒022399466  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒021978635  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒023581027  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒020720769  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒019682567  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒021659545000000002  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒023247402  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒024589501000000003  ———— )

テスト終了!

 

約64メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp2044166890552158221.txt に作成します。
テスト用一時ファイルのサイズは、67108929 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒057892566000000006  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒058601767000000006  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒043844631  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒042067168  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒041638081  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒046523542  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒040943413000000005  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒038577977  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒042847058  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒045195318000000005  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒039039437  ———— )

テスト終了!

 

約128メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp7188302575166935320.txt に作成します。
テスト用一時ファイルのサイズは、134217771 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒11521400400000001  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒11788168500000001  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒08361375  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒08419346400000001  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒082537891  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒090252891  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒080295004  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒075165433  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒086926218  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒090565376  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒10305452100000001  ———— )

テスト終了!

 

約256メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp2576486197093097661.txt に作成します。
テスト用一時ファイルのサイズは、268435542 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒222832253  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒22093158100000002  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒15506372000000002  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒15883765  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒15490747900000001  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒16721791900000002  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒16354870200000002  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒147236411  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒166499799  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒17514531700000002  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒19809278700000002  ———— )

テスト終了!

 

約512メガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp8990442498363311781.txt に作成します。
テスト用一時ファイルのサイズは、536870997 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒48024426600000003  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒46190115600000003  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒322018374  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒347179662  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒338599217  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒361760405  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒330729955  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒299515847  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒33603955100000005  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒351710028  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒38764014300000005  ———— )

テスト終了!

 

約1ギガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp4417221917340211970.txt に作成します。
テスト用一時ファイルのサイズは、1048576026 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分0秒851719442  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分0秒8790631670000001  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分0秒6286216090000001  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分0秒62141002  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分0秒6036760210000001  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分0秒6924091010000001  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分0秒6346080350000001  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分0秒583061946  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分0秒6516133420000001  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分0秒6945191980000001  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分0秒74813046  ———— )

テスト終了!

 

約2ギガバイト

テスト用一時ファイル作成開始
テスト用一時ファイルを C:\Users\Yucchi\AppData\Local\Temp\temp4971076785814883678.txt に作成します。
テスト用一時ファイルのサイズは、2097152052 バイトです。

(○・ω・)ノ————-  FileInputStream の読み込み時間は、0時間0分1秒8658922370000002  ———— )

(○・ω・)ノ————-  BufferedInputStream の読み込み時間は、0時間0分1秒8456471320000001  ———— )

(○・ω・)ノ————-  fileChannelOpen の読み込み時間は、0時間0分1秒3322223500000001  ———— )

(○・ω・)ノ————-  fileChannelOpenDirectBuffer の読み込み時間は、0時間0分1秒25010529000000004  ———— )

(○・ω・)ノ————-  fileChannelByteBuffer の読み込み時間は、0時間0分1秒21910027500000018  ———— )

(○・ω・)ノ————-  FileChannelDirectByteBuffer の読み込み時間は、0時間0分1秒31621626700000016  ———— )

(○・ω・)ノ————-  FileChannelMappedByteBuffer の読み込み時間は、0時間0分1秒21824110800000018  ———— )

(○・ω・)ノ————-  FileChannelOpenMappedByteBuffer の読み込み時間は、0時間0分1秒150197747  ———— )

(○・ω・)ノ————-  SeekableByteChannel の読み込み時間は、0時間0分1秒5578260060000002  ———— )

(○・ω・)ノ————-  SeekableByteChannelDirectBuffer の読み込み時間は、0時間0分1秒35429876100000013  ———— )

(○・ω・)ノ————-  FilesReadAllBytes の読み込み時間は、0時間0分1秒1966073290000001  ———— )

テスト終了!

 

だいたい想像していたとおりの結果となりました。

java.nio.channels.FileChannel クラスの public static FileChannel open(Path path, OpenOption… options) throws IOException を使って

ファイル・チャネルを取得して java.nio.MappedByteBuffer クラスを使って読み込むのが最速のようです。

ただし、java.nio.ByteBuffer クラスを使う処理では byteバッファの capacity(容量)をどれくらいに設定して良いのか解らなかったので適当にやったのでご容赦ください。

ネットで少しばかり調べたけど「これが BEST!」ってのは見当たらなかった。

今、ブログを書き終わろうとしているんだけど・・・

何故、こんなプログラムを組んでゴニョゴニョしようと思い立ったか思い出せずにモヤモヤしている。

Hatena タグ: