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);

並列にするか、アクセスのシリアル化が多すぎることで速度を上げる方法はありますか?

所見:

  • bodyA()bodyB()は、bodyContact コンテナー内で何度も繰り返されるオブジェクトです。
  • 今のところparallel_reduce()、1 つの乗算 (クリティカル セクション) のみを実行しますが、より複雑になります。
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 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 に答える