1. ホーム
  2. java

[解決済み] FileInputStreamを使用する場合、理想的なバッファサイズはどのように決定するのですか?

2022-05-09 19:51:08

質問

ファイルからMessageDigest(ハッシュ)を作成するメソッドがあるのですが、これを大量のファイル(>=100,000)に対して実行する必要があります。パフォーマンスを最大化するために、ファイルからの読み込みに使用するバッファをどの程度の大きさにすればよいでしょうか?

ほとんどの人は基本的なコードを知っていると思います(念のためここで繰り返します)。

MessageDigest md = MessageDigest.getInstance( "SHA" );
FileInputStream ios = new FileInputStream( "myfile.bmp" );
byte[] buffer = new byte[4 * 1024]; // what should this value be?
int read = 0;
while( ( read = ios.read( buffer ) ) > 0 )
    md.update( buffer, 0, read );
ios.close();
md.digest();

スループットを最大化するための理想的なバッファのサイズは?これはシステムに依存するのは分かっていて、OS、FileSystem, HDDに依存し、他のハードウェア/ソフトウェアが混在している可能性があります。

(私はややJava初心者なので、これは私が知らないJava APIコールがあるだけかもしれないことを指摘しておきます)。

編集する どのようなシステムで使われるのか事前に分からないので、一概に決めつけることはできませんが。(そのためにJavaを使っています)。

編集する 上のコードは、投稿を小さくするためにtry..catchなどが抜けています。

解決方法は?

最適なバッファサイズは、ファイルシステムのブロックサイズ、CPUのキャッシュサイズ、キャッシュのレイテンシーなど、多くの事柄に関連しています。

ほとんどのファイルシステムは、4096または8192のブロックサイズを使用するように設定されています。 理論的には、ディスクブロックより数バイト多く読み取るようにバッファサイズを設定すると、ファイルシステムでの操作が極めて非効率になります(例えば、一度に4100バイト読み取るようにバッファを設定した場合、各読み取りにファイルシステムで2ブロック読み取る必要が生じます)。 ブロックがすでにキャッシュにある場合、RAM -> L3/L2キャッシュのレイテンシという代償を支払うことになります。 運悪くブロックがまだキャッシュにない場合、ディスク->RAMのレイテンシの代償を支払うことになります。

このため、ほとんどのバッファのサイズは2の累乗であり、一般にディスクのブロックサイズより大きい(または等しい)ことがわかります。 つまり、1つのストリームリードが複数のディスクブロックリードになる可能性がありますが、これらのリードは常にフルブロックを使用するため、無駄なリードが発生しないのです。

ディスクから読み取られたブロックは、次の読み取りを行うときにまだメモリ内にあるため(結局のところ、ここではシーケンシャル読み取りを行っています)、次の読み取りで RAM -> L3/L2 キャッシュのレイテンシを支払うことになりますが、ディスク-> RAM レイテンシは発生しないため、通常のストリーミング シナリオではこれがかなり相殺されます。 そのため、次の読み出し時に RAM の L3/L2 キャッシュのレイテンシを支払うことになりますが、ディスクのレイテンシを支払う必要はありません。

ですから、もし異なるキャッシュサイズでテストを行った場合(私自身は行っていませんが)、おそらくファイルシステムブロックのサイズまでなら、キャッシュサイズの大きな影響が見られると思います。 それ以上では、物事はすぐに平準化されると思われます。

があります。 トン L3 -> L2キャッシュの転送を理解するだけでも気が遠くなるほど複雑で、CPUの種類によって変化します)。

これが「現実世界」の答えにつながります。 もしあなたのアプリが99%そうなら、キャッシュサイズを8192に設定し、次に進みましょう(さらに良いのは、パフォーマンスよりもカプセル化を選び、BufferedInputStreamを使って詳細を隠蔽することです)。 ディスクスループットに大きく依存する1%のアプリの場合、異なるディスク相互作用戦略を交換できるように実装を工夫し、ユーザーがテストして最適化できるようにノブやダイヤルを提供します(または自己最適化システムを考え出します)。