2500 X 80000 の double 配列を含む非常に大きなシングルトン オブジェクトがあります。マルチスレッド環境でアクセスしようとすると、スレッド数が増えるとオブジェクトへのアクセス時間が長くなります。スレッドの数に関係なく、オブジェクトのアクセス時間を同じに保つ方法があれば。
私はちょうど配列を読んでいます。配列に変更はありません。コードに同期はありません
2500 X 80000 の double 配列を含む非常に大きなシングルトン オブジェクトがあります。マルチスレッド環境でアクセスしようとすると、スレッド数が増えるとオブジェクトへのアクセス時間が長くなります。スレッドの数に関係なく、オブジェクトのアクセス時間を同じに保つ方法があれば。
私はちょうど配列を読んでいます。配列に変更はありません。コードに同期はありません
この問題の考えられる原因の 1 つは、効果のないキャッシュです。キャッシングは、キャッシュからラインをプッシュするのに十分な他のキャッシュ アクティビティが存在する前に、スレッドがラインに戻ることに依存します。スレッドの数が増えると、スレッドが回線を再利用する確率が低下します。
可能であれば、自然な順序で配列にアクセスし、2 番目のインデックスが最も速く変化するようにします。これにより、ラインができるだけ早く再利用され、各スレッドが適切に実行するために必要なキャッシュ領域の量が削減されます。
試行可能な解決策は、セマフォなどを使用して、配列を同時に読み取るスレッドの数を、最大のスループットが得られる数に制限することです。それは 1 より大きいかもしれませんが、無制限ではありません。
もう 1 つの解決策は、プロセッサの数を増やして、スレッドの数に比例してキャッシュ領域を増やすことです。
3 番目のオプションは、非常に多くのスレッドを使用して再検討することです。有限のスレッドプールと、それらが処理するタスクのキューを持つ方が効率的かもしれません。
あなたがしているのは読書だけなら、最も効率的なソフトウェアの解決策があります。問題になる可能性が高いのは、リソースを使い果たしていることです。たとえば、CPU よりも多くのスレッドがあるか、キャッシュに効率的に収まるよりも多くのデータがあります。
たとえば、スレッドが 1 つある場合、L3 キャッシュ (12 MB など) に完全にアクセスできます。2 つのスレッドがある場合、オーバーラップがなければ、各 CPU はキャッシュの半分を使用できます。24 個のスレッドがある場合、各 CPU は 0.5 MB しか持たず、競合の激しいリソースを共有する必要があります。
私が行ったテストでは、何をしているかにもよりますが、わずか 2 ~ 3 スレッドで L3 キャッシュの帯域幅を最大化できます。
ところで:どちらかを行うと、キャッシュ効率が向上するはずです。
私はちょうど配列を読んでいます。配列に変更はありません。コードに同期はありません
ある場所で、各クリティカル スレッドがそれぞれのマシンで実行されているのを見たことがあります。これにより、一定のパフォーマンスが保証されます。ただし、ハードウェアを最大限に活用し、ハードウェアに制限があることを認識するオプションを検討する必要があると思います (予算など)。
私は最終的に私の問題の解決策を見つけました。データを 2 次元配列に格納する代わりに、データを 1 次元配列に格納しました。結果は、同じものを 2 次元配列に格納するよりもはるかに高速です。明らかに、Java は 1 次元配列ほど効率的に 2 次元配列を処理しません。