Параллельная обработка столкновительных пар

Я пишу некоторый код для параллельной обработки коллизий, ожидаемый результат будет иметь ускорение для каждого потока, но я не получаю никакого ускорения при обработке данных, потому что у меня есть критический раздел внутри parallel_reduce() и я считаю, что это слишком много сериализует доступ к объектам. Вот как выглядит код:

do {
totalVel = 0.;
#pragma omp parallel for
for (unsigned long i = 0; i < bodyContact.size(); i++) {
totalVel += bodyContact.at(i).bodyA()->parallel_reduce();
totalVel += bodyContact.at(i).bodyB()->parallel_reduce();
}
} while (totalVel >= 0.00001);

Есть ли способ повысить скорость, сделав его параллельным, или слишком много сериализации доступа?

Замечания:

  • Боде () а также bodyB () являются объектами, которые многократно повторяются внутри контейнера bodyContact.
  • Теперь parallel_reduce() только делает одно умножение (критический раздел), но будет более сложным.
double parallel_reduce(){
#pragma omp critical
this->vel_ *= 0.99;
return vel_.length();
}

Фактические сроки:

  • серийный, 25,635
  • параллель, 123.559

0

Решение

Всегда есть затраты на использование конструкций OpenMP, поэтому избегайте использования параллели внутри цикла, следуя реализации, которую он может запускать каждый раз, когда новые потоки, вместо повторного пробуждения предыдущих запущенных потоков.

На самом деле, если bodyContact.size () невелик, а do {} с большим числом шагов и параллелизм_скорости очень быстр, очень трудно добиться масштабируемости с помощью нескольких прагм OpenMP.

#pragma omp parallel shared(totalVel) shared(bodyContact)
{
do {
totalVel = 0.;
#pragma omp for reduce(+:totalVel)
for (unsigned long i = 0; i < bodyContact.size(); i++) {
totalVel += bodyContact.at(i).bodyA()->parallel_reduce();
totalVel += bodyContact.at(i).bodyB()->parallel_reduce();
}
} while (totalVel >= 0.00001);
}
1

Другие решения

Вышеприведенное, вероятно, не только медленнее, но, скорее всего, неверно; все темы пытаются обновить тот же totalVel. Тонны условий гонки, а также разногласия, аннулирование кэша и т. Д.

Предполагая, что parallel_reduce() все в порядке, вы хотели бы что-то более похожее

do {
totalVel = 0.;
#pragma omp parallel for default(none) shared(bodyContact) reduction(+:totalVel)
for (unsigned long i = 0; i < bodyContact.size(); i++) {
totalVel += bodyContact.at(i).bodyA()->parallel_reduce();
totalVel += bodyContact.at(i).bodyB()->parallel_reduce();
}
} while (totalVel >= 0.00001);

который будет делать сокращение на totalVel правильно.

0

По вопросам рекламы [email protected]