Я пишу некоторый код для параллельной обработки коллизий, ожидаемый результат будет иметь ускорение для каждого потока, но я не получаю никакого ускорения при обработке данных, потому что у меня есть критический раздел внутри 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);
Есть ли способ повысить скорость, сделав его параллельным, или слишком много сериализации доступа?
Замечания:
parallel_reduce()
только делает одно умножение (критический раздел), но будет более сложным.double parallel_reduce(){
#pragma omp critical
this->vel_ *= 0.99;
return vel_.length();
}
Фактические сроки:
Всегда есть затраты на использование конструкций 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);
}
Вышеприведенное, вероятно, не только медленнее, но, скорее всего, неверно; все темы пытаются обновить тот же 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
правильно.