FileInputStreamを使用する場合、理想的なバッファサイズをどのように決定しますか?

StackOverflow https://stackoverflow.com/questions/236861

質問

ファイルから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のレイテンシは非常に遅いため、対処している他のレイテンシをほとんど圧倒します。

そのため、異なるキャッシュサイズでテストを実行した場合(自分でこれを行っていない場合)、おそらくキャッシュサイズがファイルシステムブロックのサイズまで大きな影響を与えると思われます。その上で、私は物事がかなり急速に平準化すると思う。

ここには ton の条件と例外があります-システムの複雑さは実際には非常に驚異的です(L3でハンドルを取得するだけです-> L2キャッシュ転送は気が遠くなるほど複雑で、変化します)すべてのCPUタイプで)。

これは「現実世界」の答えにつながります:アプリが99%のような場合、キャッシュサイズを8192に設定して先に進みます(さらに良いことに、パフォーマンスよりもカプセル化を選択し、BufferedInputStreamを使用して詳細を非表示にします)。ディスクスループットに大きく依存するアプリの1%を使用している場合は、さまざまなディスクインタラクション戦略を交換できるように実装を作成し、ユーザーがテストおよび最適化できるようにノブとダイヤルを提供します(または、自己最適化システム)。

他のヒント

はい、おそらくさまざまなことに依存しています-しかし、それが非常に大きな違いを生むとは思いません。私は、メモリ使用量とパフォーマンスの間の良いバランスとして16Kまたは32Kを選ぶ傾向があります。

例外がスローされた場合でもストリームが確実に閉じられるように、コードにtry / finallyブロックを含める必要があることに注意してください。

ほとんどの場合、それほど重要ではありません。 4Kや16Kなどの適切なサイズを選択して、そのまま使用します。これがアプリケーションのボトルネックであることを肯定的なら、最適なバッファサイズを見つけるためにプロファイリングを開始する必要があります。小さすぎるサイズを選択すると、余分なI / O操作と余分な関数呼び出しを行うのに時間を浪費します。大きすぎるサイズを選択すると、多くのキャッシュミスが見られるようになり、実際に速度が低下します。 L2キャッシュサイズより大きいバッファーを使用しないでください。

理想的なケースでは、1回の読み取り操作でファイルを読み取るのに十分なメモリが必要です。 システムがファイルシステム、アロケーションユニット、HDDを自由に管理できるようにするため、これが最高のパフォーマンスを発揮します。 実際には、ファイルサイズを事前に知ることができます。4K(NTFSの既定の割り当て単位)に切り上げられた平均ファイルサイズを使用するだけです。 そして何よりも、複数のオプションをテストするためのベンチマークを作成してください。

BufferedStreams / readersを使用してから、そのバッファーサイズを使用できます。

BufferedXStreamsはバッファーサイズとして8192を使用していると思いますが、Ovidiuが言ったように、おそらく多くのオプションでテストを実行する必要があります。最適なサイズは、ファイルシステムとディスクの構成に依存します。

Java NIOのFileChannelとMappedByteBufferを使用してファイルを読み取ると、FileInputStreamが関係するソリューションよりもはるかに高速なソリューションになる可能性があります。基本的に、大きなファイルをメモリマップし、小さなファイルには直接バッファを使用します。

BufferedInputStreamのソースには、private static int DEFAULT_BUFFER_SIZE = 8192;
があります。 そのため、そのデフォルト値を使用するのは大丈夫です。
しかし、さらに多くの情報を把握できれば、より価値のある回答が得られます。
たとえば、TCP / IPのペイロードのため、adslは1454バイトのバッファを優先する場合があります。ディスクの場合、ディスクのブロックサイズに一致する値を使用できます。

他の回答で既に述べたように、BufferedInputStreamsを使用します。

その後、バッファサイズは実際には問題ではないと思います。プログラムはI / Oバウンドであり、BISのデフォルトを超えるバッファサイズの増加は、パフォーマンスに大きな影響を与えません。

または、プログラムはMessageDigest.update()内でCPUにバインドされており、ほとんどの時間はアプリケーションコードに費やされていないため、微調整しても役に立ちません。

(うーん...複数のコアがあれば、スレッドが役立つかもしれません。)

1024はさまざまな状況に適していますが、実際には、バッファサイズを大きくしたり小さくしたりするとパフォーマンスが向上する場合があります。

これは、ファイルシステムブロックを含む多くの要因に依存します。 サイズとCPUハードウェア。

また、バッファサイズに2のべき乗を選択することも一般的です。 ハードウェアは、2のべき乗であるファイルサイズとキャッシュサイズで構成されています。 クラスを使用すると、コンストラクタでバッファサイズを指定できます。何も提供されない場合、彼らは デフォルト値を使用します。これは、ほとんどのJVMで2の累乗です。

選択するバッファサイズに関係なく、最大のパフォーマンス向上 seeは、バッファなしファイルアクセスからバッファ付きファイルアクセスに移行しています。バッファサイズを調整すると パフォーマンスをわずかに改善しますが、非常に小さいまたは非常に小さい バッファサイズが大きい場合、重大な影響はほとんどありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top