Я реализовал конвейерный подход. Я собираюсь пройти по дереву, и мне нужны определенные значения, которые не доступны заранее ... поэтому я должен пройти по дереву параллельно (или раньше) и еще раз для каждого узла, в котором я хочу сохранить значения (например, lowerndantCount) ).
Таким образом, я перебираю дерево, затем из конструктора я вызываю метод, который вызывает новый поток, запущенный через ExecutorService. Вызываемый объект:
@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, который пересекает дерево для каждого узла и подсчитывает потомков и модификации (на самом деле я объединяю две ревизии дерева). Ну, mDescendantsQueue и mModificationQueue являются BlockingQueues. Вначале у меня была только функция followndantsQueue, и я снова обошел дерево, чтобы получить модификации каждого узла (считая изменения, сделанные в поддереве текущего узла). Тогда я подумал, почему бы не сделать как параллельно, так и реализовать конвейерный подход. К сожалению, производительность, казалось, уменьшалась каждый раз, когда я выполнял еще один многопоточный «шаг».
Возможно, потому что XML-дерево обычно не такое глубокое, а издержки параллелизма слишком тяжелы: - /
Сначала я делал все последовательно, что было самым быстрым:
- пересекая дерево
- для каждого узла перебрать потомков и вычислить downndantCount иificationCount
После использования конвейерного подхода с BlockingQueues кажется, что производительность снизилась, но я фактически не принимал никаких временных мер, и мне пришлось бы отменить многие изменения, чтобы вернуться :( Возможно, производительность увеличивается с увеличением числа процессоров, потому что я только Core2Duo для тестирования прямо сейчас.
С наилучшими пожеланиями,
Johannes