ショートバージョンはタイトルにあります。
長いバージョン: Java を使用して科学的最適化のためのプログラムに取り組んでいます。プログラムのワークロードは、並列フェーズと直列フェーズに分けることができます。並列フェーズとは、高度に並列化可能な作業が実行されていることを意味します。プログラムを高速化するために (数時間または数日間実行されます)、使用しているマシンの CPU コアの数 (通常は 4 または 8) に等しい数のスレッドを作成し、それらの間で作業を分割します。次に、これらのスレッドを開始して join() してから、シリアル フェーズに進みます。
ここまでは順調ですね。私を悩ませているのは、並列フェーズの CPU 使用率とスピードアップが「理論上の最大値」にほど遠いことです。たとえば、4 つのコアがある場合、「使用率」は 350 ~ 400% になると予想されます (top で報告されているように)。代わりに、180 から約 310 の間で跳ね返ります。1 つのスレッドのみを使用すると、100% の CPU 使用率が得られます。
スレッドがフルスピードで実行されない唯一の理由は次のとおりです。 - I/O によるブロッキング - 同期によるブロッキング
並列スレッドでは I/O はまったく行われておらず、同期も行われていません。スレッドによって共有される唯一のデータ構造は読み取り専用であり、基本型または (非同時) コレクションのいずれかです。だから私は他の説明を探しています。1 つの可能性として、複数のスレッドがガベージ コレクションのために繰り返しブロックしている可能性がありますが、それはメモリ プレッシャーのある状況でのみ意味があるように思われ、必要な最大ヒープ領域をはるかに超えて割り当てています。
任意の提案をいただければ幸いです。
更新:誰かが興味を持っている場合に備えて、さらに調査した後、一般的なパフォーマンスのためにコードを微調整し、同期とは何の関係もありませんが、使用率が向上していることを確認しました。ただし、いくつかの変更により、特に新しいヒープ割り当てが少なくなるはずでした。イテレータと一時的なボックス化された数値の使用をいくつか取り除きました (ハイパフォーマンス Java コンピューティング用の CERN "Colt" ライブラリは、ここで役立ちました: IntArrayList のようなコレクションを提供します)。 、基本型の DoubleArrayList など)。したがって、おそらくガベージコレクションが原因だと思います。