1

パイプラインアプローチを実装しました。ツリーをトラバースするつもりですが、事前に利用できない特定の値が必要です...したがって、ツリーを並行して(または前に)トラバースし、値を保存したいノードごとにもう一度トラバースする必要があります(たとえば、descendantCount )。

そのため、ツリーを介して対話し、コンストラクターから、ExecutorService を通じて開始された新しいスレッドを呼び出すメソッドを呼び出しています。送信される Callable は次のとおりです。

    @Override
    public Void call() throws Exception {
        // Get descendants for every node and save it to a list.
        final ExecutorService executor =
            Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        int index = 0;
        final Map<Integer, Diff> diffs = mDiffDatabase.getMap();
        final int depth = diffs.get(0).getDepth().getNewDepth();
        try {
            boolean first = true;
            for (final AbsAxis axis = new DescendantAxis(mNewRtx, true); index < diffs.size()
                && ((diffs.get(index).getDiff() == EDiff.DELETED && depth < diffs.get(index).getDepth()
                    .getOldDepth()) || axis.hasNext());) {
                if (axis.getTransaction().getNode().getKind() == ENodes.ROOT_KIND) {
                    axis.next();
                } else {
                    if (index < diffs.size() && diffs.get(index).getDiff() != EDiff.DELETED) {
                        axis.next();
                    }

                    final Future<Integer> submittedDescendants =
                        executor.submit(new Descendants(mNewRtx.getRevisionNumber(), mOldRtx
                            .getRevisionNumber(), axis.getTransaction().getNode().getNodeKey(), mDb
                            .getSession(), index, diffs));
                    final Future<Modification> submittedModifications =
                        executor.submit(new Modifications(mNewRtx.getRevisionNumber(), mOldRtx
                            .getRevisionNumber(), axis.getTransaction().getNode().getNodeKey(), mDb
                            .getSession(), index, diffs));
                    if (first) {
                        first = false;
                        mMaxDescendantCount = submittedDescendants.get();
                        // submittedModifications.get();
                    }
                    mDescendantsQueue.put(submittedDescendants);
                    mModificationQueue.put(submittedModifications);
                    index++;
                }
            }

            mNewRtx.close();
        } catch (final AbsTTException e) {
            LOGWRAPPER.error(e.getMessage(), e);
        }
        executor.shutdown();
        return null;
    }

したがって、すべてのノードに対して、すべてのノードのツリーをトラバースし、子孫と変更をカウントする新しい Callable を作成しています (実際には、2 つのツリー リビジョンを融合しています)。さて、mDescendantsQueue と mModificationQueue は BlockingQueue です。最初は、descendantsQueue しか持っておらず、ツリーをもう一度トラバースして、すべてのノードの変更を取得しました (現在のノードのサブツリーで行われた変更を数えます)。次に、両方を並行して実行し、パイプライン化されたアプローチを実装しない理由を考えました。悲しいことに、別のマルチスレッドの「ステップ」を実装するたびに、パフォーマンスが低下したように見えました。

おそらく、XML ツリーは通常それほど深くなく、同時実行オーバーヘッドが重すぎるためです :-/

最初はすべてを順番に実行しましたが、これが最も高速でした:

BlockingQueues でパイプライン化されたアプローチを使用した後、パフォーマンスが低下したように見えますが、実際には時間測定を行っていないため、多くの変更を元に戻して元に戻す必要があります:( CPU が増えるとパフォーマンスが向上する可能性があります。今すぐテストする Core2Duo。

よろしく、
ヨハネス

4

2 に答える 2

1

おそらくこれが役立つはずです:アマダールの法則、基本的には、生産性の向上は、同期によって処理する必要があるコードの割合に (反比例して) 依存するということです。したがって、計算リソースを増やして増やしても、結果が良くなることはありません。理想的には、(合計部分に対する同期部分) の比率が低い場合、(プロセッサの数 +1) を使用すると最高の出力が得られるはずです (ただし、ネットワークまたは他の I/O を使用している場合は、サイズを大きくすることができます)。プールの)。したがって、上記のリンクからフォローアップして、役立つかどうかを確認してください

于 2011-09-09T14:49:00.013 に答える
0

あなたの説明から、あなたは再帰的にスレッドを作成しているように聞こえます。各スレッドは1つのノードを処理してから、新しいスレッドを生成しますか?これは正しいです?もしそうなら、私はあなたがパフォーマンスの低下に苦しんでいることに驚いていません。

単純な再帰下降法が実際にこれを行うための最良の方法かもしれません。ここでは、マルチスレッドがどのように利点を得るのかわかりません。

于 2011-09-09T13:10:24.383 に答える