4

私のプログラムは、以下に示すように 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 の奥深くで、誰かがメモリ バリアを越えています (キャッシュを汚染しています)。しかし、どうすればそれを見つけて修正したり、対処したりできますか?

4

2 に答える 2

1

異なるコアにスレッド/タスクを割り当てるため、過負荷が発生する可能性があります。また、プログラムが完全に並列化可能であることを確認しますか?実際、一部のプログラムでは、使用可能なすべてのCPUを常に100%効率的に使用できるとは限らず、タスクのディスパッチにかかる時間によって、プログラムの速度が低下する可能性があります。

于 2012-07-26T17:10:32.670 に答える
0

molList(またはmol) 変数のサイズにしきい値を使用して、小さすぎるデータ セットでのフォークを回避する必要があると思います。

フレームワークを理解するためだけに fork/join で少し遊んでいましたが、最初の例ではしきい値が考慮されていませんでした。明らかに、私はひどいパフォーマンスを得ました。問題のサイズの適切な制限を修正すると、うまくいきました。

しきい値の適切な値を見つけるには、少し時間をかけてさまざまな値を試し、パフォーマンスがどのように変化するかを確認する必要があります。

したがって、次のようにメソッドifの先頭に an を配置します。compute

@Override
protected Long compute() {
    if (mol.getSize() < THRESHOLD) //getSize or whatever gives you size of problem
         return noForkJoinCompute(mol); //noForkJoinCompute gives you count without FJ

    long count = 0;
    try {
        if (mol.isComplete(satCheck)) {
            count = 1;
        }
    ...
于 2013-02-03T22:15:09.073 に答える