私のプログラムは、以下に示すように fork/join を使用して、何千ものタスクを実行します。
private static class Generator extends RecursiveTask<Long> {
final MyHelper mol;
final static SatChecker satCheck = new SatChecker();
public Generator(final MyHelper mol) {
super();
this.mol = mol;
}
@Override
protected Long compute() {
long count = 0;
try {
if (mol.isComplete(satCheck)) {
count = 1;
}
ArrayList<MyHelper> molList = mol.extend();
List<Generator> tasks = new ArrayList<>();
for (final MyHelper child : molList) {
tasks.add(new Generator(child));
}
for(final Generator task : invokeAll(tasks)) {
count += task.join();
}
} catch (Exception e){
e.printStackTrace();
}
return count;
}
}
私のプログラムでは、isComplete メソッドと extends メソッドのためにサードパーティのライブラリを多用しています。拡張メソッドもネイティブ ライブラリを使用します。MyHelper クラスに関する限り、共有変数やタスク間の同期はありません。
Linux の taskset コマンドを使用して、アプリケーションで使用されるコアの数を制限しています。約 10 コア (約 60 秒) を使用すると、最高の速度が得られます。これは、10 を超えるコアを使用するとアプリケーションの速度が低下することを意味し、16 コアは 6 コアと同じ時間 (約 90 秒) で終了します。
選択したコアが 100% ビジーであるため、さらに混乱します (時々ガベージ コレクションを除く)。このような速度低下の原因を知っている人はいますか? そして、この問題を解決するにはどこを見ればよいでしょうか?
PS: Scala/akka で ThreadPoolExecutor を使用して実装も行いましたが、同様の結果が得られました (fork/join よりは遅いですが)。
PPS: 私の推測では、MyHelper または SatCheck の奥深くで、誰かがメモリ バリアを越えています (キャッシュを汚染しています)。しかし、どうすればそれを見つけて修正したり、対処したりできますか?