[解決済み] Java NIOのFileChannelとFileOutputstreamの性能/有用性
質問
nioを使用した場合のパフォーマンス(または利点)に違いがあるかどうかを把握しようとしています。
FileChannel
と通常の
FileInputStream/FileOuputStream
を使用して、ファイルシステムへのファイルの読み取りと書き込みを行います。私のマシンでは、どちらも同じレベルで動作していることが確認されましたし、何度も
FileChannel
の方が遅いです。この2つの方法の比較の詳細を教えてください。私が使用したコードは以下の通りです。
350MB
. ランダムアクセスやその他の高度な機能を必要としない場合、ファイルI/OにNIOベースのクラスを使用することは良い選択でしょうか?
package trialjavaprograms;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class JavaNIOTest {
public static void main(String[] args) throws Exception {
useNormalIO();
useFileChannel();
}
private static void useNormalIO() throws Exception {
File file = new File("/home/developer/test.iso");
File oFile = new File("/home/developer/test2");
long time1 = System.currentTimeMillis();
InputStream is = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(oFile);
byte[] buf = new byte[64 * 1024];
int len = 0;
while((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
fos.close();
is.close();
long time2 = System.currentTimeMillis();
System.out.println("Time taken: "+(time2-time1)+" ms");
}
private static void useFileChannel() throws Exception {
File file = new File("/home/developer/test.iso");
File oFile = new File("/home/developer/test2");
long time1 = System.currentTimeMillis();
FileInputStream is = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(oFile);
FileChannel f = is.getChannel();
FileChannel f2 = fos.getChannel();
ByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024);
long len = 0;
while((len = f.read(buf)) != -1) {
buf.flip();
f2.write(buf);
buf.clear();
}
f2.close();
f.close();
long time2 = System.currentTimeMillis();
System.out.println("Time taken: "+(time2-time1)+" ms");
}
}
解決方法は?
私の経験では、ファイルサイズが大きい場合、以下のようになります。
java.nio
よりも高速です。
java.io
.
しっかり高速化。
>250%台とか。 とはいえ、私は明らかなボトルネックを排除しており、あなたのマイクロベンチマークが苦しむかもしれないことを示唆しています。 調査する可能性のある分野です。
バッファの大きさ 基本的に持っているアルゴリズムは
- ディスクからバッファにコピー
- バッファからディスクへのコピー
私自身の経験では、このバッファの大きさは 熟 チューニングのために。 私は、アプリケーションのある部分では4KB、別の部分では256KBに落ち着きました。 あなたのコードは、このような大きなバッファで苦しんでいるのではないでしょうか。 1KB、2KB、4KB、8KB、16KB、32KB、64KBのバッファでベンチマークを実行し、それを証明してみてください。
同じディスクに読み書きするようなjavaベンチマークを実行しないこと。
もしそうなら、あなたは本当にJavaではなく、ディスクをベンチマークしていることになります。 また、CPUがビジー状態でないのなら、何か他のボトルネックが発生している可能性がありますね。
必要なければバッファを使わないでください。
ターゲットが他のディスクやNICである場合、なぜメモリにコピーするのですか? 大きなファイルでは、発生するレイテンシは自明ではありません。
他の人が言っているように
FileChannel.transferTo()
または
FileChannel.transferFrom()
. ここでの重要な利点は、JVMがOSのDMAへのアクセス(
ダイレクトメモリーアクセス
) があれば、それを使用します。
(これは実装に依存しますが、汎用CPU上の最近のSunやIBMのバージョンは問題ないです)。
データはディスクからバスへ、そして目的地へ...RAMやCPUを経由する回路をバイパスして直接送られるのです。
私が日夜取り組んでいるWebアプリは、IOが非常に重いです。 マイクロベンチマークや実世界のベンチマークもやってみたよ。 その結果は私のブログにアップされているので、見てみてください。
本番データ・環境を利用する
マイクロベンチマークは歪みやすい。 可能であれば、想定したハードウェアで、想定した負荷で、想定した通りのデータを収集するよう努力してください。
私のベンチマークが堅実で信頼できるのは、ログを収集し、負荷のかかったシステム、高性能なシステムで実施されたからです。 はありません。 私は、JVMが私のハードディスクを操作するのを激しく観察しながら、ノートブックの7200回転の2.5" SATAドライブを操作しました。
何を使っているのですか? それは重要です。
関連
-
Javaクラスローダーにソースコードから潜り込む
-
this()の呼び出しはコンストラクタ本体の最初の文でなければならない 例外解決と原因分析
-
Java コンパイルエラー - スレッド "main" で例外 java.lang.Error: 未解決のコンパイル問題です。
-
xxx:jarのアーティファクトディスクリプタの読み込みに失敗した問題は解決しました。
-
javaコンパイル時のエラー:不正な文字 '\ufeff' に対する解決策です。
-
javaでクラスを作成すると、enclosing classでないように見える
-
java 例外。Javaツールの初期化
-
コミットには何も追加されないが、未追跡のファイルが存在し、gitで未追跡のファイルに対する完璧な解決策
-
[解決済み] Javaにおける例外処理によるパフォーマンスへの影響とは?
-
[解決済み】Java FileOutputStream ファイルが存在しない場合にファイルを作成する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
エラーが報告されました。リソースの読み込みに失敗しました:サーバーは500(内部サーバーエラー)のステータスで応答しました。
-
Dateが型に解決できない問題を解決する
-
java Mail send email smtp is not authenticated by TLS encryption solution.
-
eclipse の実行時に java 仮想マシンが見つからなかった
-
サーブレットクラスのインスタンス化エラーの解決法
-
Methodのinvokeメソッド実装のJavaリフレクション
-
spring-boot 401 このリソースにアクセスするには完全な認証が必要です エラー解決
-
Exception: java.util.NoSuchElementException: 行が見つかりません
-
HttpClientがGZIP形式でない場合の対処法
-
javax.net.ssl.SSLException: 読み取りエラー: ssl=0xdeae5100: システムコール中の I/O エラー、接続 res