0

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

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

观察:

  • 身体A()身体B()是在 bodyContact 容器内重复很多次的对象。
  • 目前parallel_reduce()只做一次乘法(临界区),但会变得更复杂。
double parallel_reduce(){
    #pragma omp critical
        this->vel_ *= 0.99;
        return vel_.length();
    }

实际时间:

  • 序列号,25.635
  • 平行,123.559
4

2 回答 2

1

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

事实上,如果 bodyContact.size() 很小并且 do {} 步数很大并且 parallel_reduce 非常快,那么仅使用几个 OpenMP pragma 就很难具有可伸缩性。

#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);
}
于 2012-11-14T09:58:32.427 回答
0

以上可能不仅速度较慢,而且很可能是错误的;所有线程都在尝试更新相同的 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

于 2012-11-14T01:59:34.010 回答