1

ネストされた for ループの並列化に問題があります。コードは次のようになります

  for( k = 0; k < m; k++ ) {
    for( i = 0; i < k; i++ ) {
      s = 0.0;
#pragma omp parallel for default(none) shared(i, k, q, m, n) private(j) reduction(+:s)
      for( j = 0; j < n; j++ ) {
        s += q[ i ][ j ] * q[ k ][ j ];
      }
    }
  }

このコードは機能しますが、'k' および 'i' ループの下でスレッドを何度も作成および破棄するときのオーバーヘッドが原因で、実行速度が非常に遅くなります。

理想的には、私はこのようなものが欲しい

#pragma omp parallel default(none) shared(i, k, q, m, n, s) private(j)
  for( k = 0; k < m; k++ ) {
    for( i = 0; i < k; i++ ) {
      s = 0.0;
#pragma omp for reduction(+:s)
      for( j = 0; j < n; j++ ) {
        s += q[ i ][ j ] * q[ k ][ j ];
      }
    }
  }

並列領域が一度だけ作成される場所。しかし、私は間違った結果を得ています。これは、変数「s」が共有されているためだと思います。

「s」を共有して削減を実行する方法はありますか?

ありがとう!

PS 'k' または 'i' ループは以前の反復に依存しているため、並列化できません。

4

1 に答える 1

1

それは私だけですか、それともループ内にi省略したコードの一部がありますか? q[m-1][]そのコードは多くの内積を計算するだけなので、最後にはとの内積のみq[m-2][]が に格納されsます。また、与えられたように、コードにはループの反復間にデータの依存関係はありませんが、静的スケジューリングを使用して他のループを並列化すると、むしろ負荷の不均衡が発生します。動的スケジューリングを使用して、これにいくらか対抗できます。

#pragma omp parallel default(none) shared(q, m, n) \
            private(i, k, j) lastprivate(s) schedule(dynamic,1)
for( k = 0; k < m; k++ ) {
  for( i = 0; i < k; i++ ) {
    s = 0.0;
    for( j = 0; j < n; j++ ) {
      s += q[ i ][ j ] * q[ k ][ j ];
    }
  }
}

コンパイラが標準のバージョン 3.0 以降をサポートしている場合は、OpenMP タスクを使用することもできます。

@Zhenya、j ループが最も外側にある場合、C/C++ のメモリ内で隣接していないためq[i][j]、キャッシュの利点が失われます。q[i+1][j]

于 2012-05-04T10:38:17.247 に答える