并行处理冲突对

Parallel Processing Collision Pairs

本文关键字:冲突 并行处理      更新时间:2023-10-16

我正在编写一些用于并行处理碰撞的代码,预期的结果是每个线程都有一个加速,但我在数据处理上没有得到任何加速,因为我在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);

有没有办法通过并行或访问的序列化太多来获得更高的速度?

观察:

  • bodyA() 和 bodyB() 是在 bodyContact 容器中重复多次的对象。
  • 目前parallel_reduce()只做一个乘法(关键部分),但会变得更加复杂。
double parallel_reduce(){
    #pragma omp critical
        this->vel_ *= 0.99;
        return vel_.length();
    }

实际时间:

  • 序列号, 25.635
  • 并行,123.559

使用 OpenMP 构造总是有成本的,因此请避免在循环中使用并行,在实现之后,它可以在每次新线程启动时启动,而不是重新唤醒以前启动的线程。

事实上,如果 bodyContact.size() 很小,而 do {} 在步数上很大,而且parallel_reduce非常快,那么仅仅用几个 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