Я реализовал подход трубопровода. Я собираюсь пересечь дерево, и мне нужны определенные значения, которые недоступны заранее ... поэтому мне нужно пересекать дерево параллельно (или раньше) и еще раз для каждого узла, который я хочу сохранить значения (например, 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;
}
Поэтому для каждого узла он создает новый отзывной, который пересекает дерево для каждого узла и подсчитывает потомков и модификаций (я на самом деле слияния двух деревьев-пересмотров вместе). Ну, mDescendantsQueue и mModificationQueue - BlockingQueues. Сначала я имел только потомкиQueue и снова пересекал дерево, чтобы получить модификации каждого узла (подсчет изменений, сделанных в поддереве текущего узла). Тогда я подумал, почему бы не сделать оба параллельно и реализовать конвейерный подход. К сожалению, производительность, казалось, уменьшалась каждый раз, когда я реализовал другой многопоточный «шаг».
Может быть, потому что XML-дерево, как правило, не так глубоко и параллелизм-Накладные слишком тяжелы: -/
Сначала я сделал все, что последовательное, который был самым быстрым: - пересекающее деревом - для каждого узла пересекаются потомки и вычисляются потомкиCount и modifyCount
После использования конвейерного подхода с BlockingQueues кажется, что производительность уменьшилась, но я на самом деле не делал никаких временных мер, и мне пришлось бы вернуть много изменений, чтобы вернуться назад :(Может быть, производительность увеличивается с увеличением количества процессоров, потому что сейчас у меня есть только Core2Duo для тестирования.
наилучшие пожелания,
Johannes
Для чего нужен mNewRtx? Если это то, что либо не поддерживает параллелизм, либо использует синхронизацию для обработки, это, безусловно, повредит. Можете ли вы сказать, используются ли ваши два ядра все время? –
Это транзакция чтения, которая может проходить через дерево. Некоторые методы синхронизированы, но я их не использую. Я думаю, что 2 ядра необходимо использовать, потому что фрагмент кода, который я опубликовал, выполняется в другом потоке (и он порождает больше потоков для каждого узла, но максимум 2 потока из-за моего ноутбука). Я думаю, что для создания множества потоков может возникнуть проблема. Но, не считая того, в будущем это может окупиться и масштабироваться с большим количеством ядер. Вот почему я сделал это в первую очередь. – Johannes
Это * не * нерестится много потоков, потому что вы используете фиксированный пул потоков. Я уверен, что он использует оба ядра - но вы должны проверить, как * полностью * он их использует. –