Nehalem プロセッサで実行されるマルチスレッド Java アプリケーションを作成しています。ただし、4 つのスレッドから開始すると、アプリケーションのスピードアップがほとんど見られないという問題があります。
私はいくつかの簡単なテストを行いました。大きな配列を割り当て、配列内のランダムなエントリにアクセスするだけのスレッドを作成しました。そのため、スレッド数を実行しても、実行時間は変化しません (使用可能な CPU コアの数を超えていないと仮定します)。しかし、私が観察したところ、1 つまたは 2 つのスレッドを実行するとほぼ同じ時間がかかりますが、4 つまたは 8 つのスレッドを実行すると大幅に遅くなります。したがって、アプリケーションでアルゴリズムと同期の問題を解決しようとする前に、達成できる最大の可能な並列化を見つけたいと思います。
JVM オプションを使用-XX:+UseNUMA
したので、対応するスレッドの近くのメモリに配列を割り当てる必要があります。
PS スレッドが単純な数学的計算を行っている場合、4 スレッドでも 8 スレッドでも時間の低下はなかったので、スレッドがメモリにアクセスしているときに問題があると結論付けました。
助けやアイデアをいただければ幸いです。
編集
返信ありがとうございます。私は自分自身を十分に説明していないことがわかりました。
アプリケーションで同期の問題を解消する前に、実現可能な最適な並列化をチェックする簡単なテストを行いました。コードは次のとおりです。
public class TestMultiThreadingArrayAccess {
private final static int arrSize = 40000000;
private class SimpleLoop extends Thread {
public void run() {
int array[] = new int[arrSize];
for (long i = 0; i < arrSize * 10; i++) {
array[(int) ((i * i) % arrSize)]++; // randomize a bit the access to the array
}
long sum = 0;
for (int i = 0; i < arrSize; i++)
sum += array[i];
}
}
public static void main(String[] args) {
TestMultiThreadingArrayAccess test = new TestMultiThreadingArrayAccess();
for (int threadsNumber : new int[] { 1, 2, 4, 8 }) {
Statistics timer = new Statistics("Executing " + threadsNumber+ " threads"); // Statistics is a simple helper class that measures the times
timer.start();
test.doTest(threadsNumber);
timer.stop();
System.out.println(timer.toString());
}
}
public void doTest(int threadsNumber) {
Thread threads[] = new Thread[threadsNumber];
for (int i = 0; i < threads.length; i++) {
threads[i] = new SimpleLoop();
threads[i].start();
}
for (int i = 0; i < threads.length; i++)
try {
threads[i].join();
} catch (InterruptedException e) {
};
}
}
ご覧のとおり、このミニテストでは同期がまったく行われず、配列の割り当てもスレッド内にあるため、すばやくアクセスできるメモリのチャンクに配置する必要があります。また、このコードにはメモリ競合はありません。それでも 4 スレッドの場合、実行時間は 30% 低下し、8 スレッドでは実行速度が 2 倍遅くなります。コードからのように、すべてのスレッドが作業を完了するまで待ちます。スレッドの作業は独立しているため、スレッドの数は実行にかかる合計時間に影響しません。
マシンには 2 つのクアッドコア ハイパースレッド Nehalem プロセッサ (合計 16 個の CPU) がインストールされているため、8 つのスレッドでそれぞれがその CPU を排他的にキャッチできます。
より小さな配列 (20K エントリ) でこのテストを実行しようとしたとき、4 スレッドの実行時間の低下は 7% で、8 スレッドでは 14% であり、満足のいくものでした。しかし、大きな配列(40M エントリ)でランダム アクセスを実行しようとすると実行時間が劇的に増加するため、メモリの大きなチャンク(キャッシュ メモリに収まらないため?)が非アクセスでアクセスされるという問題があると思います。 -効率的な方法。
これを修正する方法はありますか?
これにより、質問がより明確になることを願っています。ありがとうございます。