Вчера я проверил свою программу эволюции ландшафта с большим набором данных (20 миллионов узлов), без сомнения, скорость работы была неприемлемой. Во время отладки я заметил, что это была определенная функция, которая замедляла всю систему. Поэтому я хотел бы добавить к нему многопоточность.Стратегия блокировки программирования OpenMP в C++ для вложенных циклов
Однако сама функция представляет собой вложенный цикл с итераторами-указателями, и я считаю, что некоторые данные должны быть заблокированы во время процесса.
В основном то, что я пытался сделать, это вычислить вкладку каждого узла. Область вкладок, как предлагается по ее названию, является продуктом (суммой) всей области от восходящего узла.
Вот код, что две функции,
for(curnode = nodIter.FirstP(); nodIter.IsActive();
curnode = nodIter.NextP()) //iterating thru a linked-list of pointers to active stream nodes (*IsActive* returns a bool value)
{
CalcDRArea(curnode, curnode->getVArea()); //calls another function and pass a pointer to current node as well as a value of its VArea
}
void CalcDRArea(NodeClass *curnode, double addedArea)
{
// As long as the current node is neither a boundary nor non-valid, add
// _addedArea_ to its total drainage area and advance to the next node downstream
while((curnode->ReachBoundary() == NonBoundary) &&
(curnode->valid()!=Nonvalid))
{
curnode->AddDrArea(addedArea); //*AddDrArea* is a simple inline function *`"drarea +=value"`*
curnode = curnode->getDownStreammNeighbor(); // *getDownstrmNbr()* reruns a pointer to the downstream node
}
}
Вот простая иллюстрация узлов и их текучий направление
A B C D
\ |/ |
E F G H
| |
I Q K L
| /
M N O P
//letters are stream nodes and slashes are their flowing directions
Мой план заключается в использовании OpenMP для реализации многопоточности в начале первой функции, для цикла , В идеале он будет создавать несколько потоков для вычисления каждого узла отдельно.
Однако, как показано на рисунке выше, процесс секвенции может обрабатывать потоки, как
A-> F -> Q -> N
B-> F -> Q -> N
C-> F -> Q -> N
легко, но это, безусловно, вызовет проблему в многопоточных условиях.
Из того, что я только что прочитал из документа OpenMP, в вровень и замок может быть правильный способ сделать это, но все же я сейчас я совершенно невежественны и там еще может быть и другие потенциальные проблемы в пределах этой петли (например, gcc ver. из OpenMP не поддерживает «! =»).
==== Обновление ====== Существует два вида областей: vArea, который является областью каждого узла; и drArea, которая является суммой площади текущего узла и области от всех ее восходящих узлов. мне было интересно, если я могу изменить текущую функцию на это:
for(active node iterator)
{
if(currentNode.hasDownStreamNode)
{
downStreamNode.drArea += currentNode.vArea + currentNode.DrArea;
}
CurrentNode.drArea += currentNode.varea;
}
Это очень легко применимо к динамическому программированию - с использованием лучшего алгоритма перед попыткой многопоточного программирования, как правило, это не плохая идея. Вы в основном делаете это в O (n^2) вместо O (n). – Voo
Не могли бы вы дать мне несколько советов по лучшему алгоритму? Я понял, что это O (n * n) и не знаю, как сделать его проще. Благодарю. – KuN
Это зависит от того, как работает ваш алгоритм, потому что он не ясен из данного кода, но основная идея заключается в том, что 'F' имеет значение' A + B + C + F', а Q имеет значение 'A + B + C + F + Q' и т. Д. Таким образом, чтобы вычислить значение одного узла, вам нужно только просмотреть уже вычисленные значения всех его предшественников * один раз *, а не итерировать все узлы из каждого стартового узла. – Voo