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