6

タイトルが非常に不明確である場合は申し訳ありません。私はこれをどのように表現すればよいかよくわかりません。

以下の方法で何とかできないかと考え中です。

#pragma omp parallel
{
    for (int i = 0; i < iterations; i++) {
        #pragma omp for
        for (int j = 0; j < N; j++)
            // Do something
    }
}

forループでプライベート指定子を省略するなどのことを無視して、内側のループを並列化できるように、外側のループの外側でスレッドをフォークできる方法はありますか? 私の理解では (間違っている場合は訂正してください)、すべてのスレッドが外側のループを実行します。for内側のループの動作についてはよくわかりませんが、遭遇した各スレッドにチャンクが分配されると思います。

私がやりたいことは、時間を分岐/結合する必要はなくiterations、外側のループで一度だけ実行することです。これは正しい戦略ですか?

並列化すべきではない別の外部ループがあった場合はどうなるでしょうか? あれは...

#pragma omp parallel
{

    for (int i = 0; i < iterations; i++) {
        for(int k = 0; k < innerIterations; k++) {
            #pragma omp for
            for (int j = 0; j < N; j++)
                // Do something

            // Do something else
        }
    }
}

OpenMP を使用する際に採用する戦略をよりよく理解できるように、OpenMP を使用して並列化された大規模なアプリケーションの例を誰かが教えてくれたら素晴らしいと思います。見つからないようです。

明確化: ループの順序を変更しない、またはブロック、キャッシュ、および一般的なパフォーマンスの考慮事項を含まないソリューションを探しています。指定されたループ構造で OpenMP でこれを行う方法を理解したいと思います。依存関係がある場合とない場合があります。// Do something依存関係があり、移動できないと仮定します。

4

3 に答える 3

3

2 つの for ループを処理した方法は、必要な動作を実現するという意味で、私には正しいように見えます。外側のループは並列化されていませんが、内側のループは並列化されています。

何が起こるかをより明確にするために、コードにいくつかのメモを追加してみます。

#pragma omp parallel
{
  // Here you have a certain number of threads, let's say M
  for (int i = 0; i < iterations; i++) {
        // Each thread enters this region and executes all the iterations 
        // from i = 0 to i < iterations. Note that i is a private variable.
        #pragma omp for
        for (int j = 0; j < N; j++) {
            // What happens here is shared among threads so,
            // according to the scheduling you choose, each thread
            // will execute a particular portion of your N iterations
        } // IMPLICIT BARRIER             
  }
}

暗黙のバリアは、スレッドが互いに待機する同期ポイントです。したがって、経験則として、内側のループよりも外側のループiterations*Nを並列化する方が望ましいです。これにより、(上記で作成したポイントではなく) 反復の単一の同期ポイントが作成されるためiterationsです。

于 2013-05-08T19:19:29.630 に答える
1

あなたの質問に答えられるかどうかわかりません。OpenMP を使い始めてまだ数か月ですが、このような質問に答えようとすると、以下に示すような hello world printf テストを実行します。それがあなたの質問に答えるのに役立つと思います。また#pragma omp for nowait、どうなるか試してみてください。

「//何かを実行し、//何か他のことを実行する」ときに、同じメモリアドレスに書き込んで競合状態を作成しないようにしてください。また、読み取りと書き込みを頻繁に行う場合は、キャッシュを効率的に使用する方法を考える必要があります。

#include "stdio.h"
#include <omp.h>
void loop(const int iterations, const int N) {
    #pragma omp parallel
    {
        int start_thread = omp_get_thread_num();
        printf("start thread %d\n", start_thread);
        for (int i = 0; i < iterations; i++) {
            printf("\titeration %d, thread num %d\n", i, omp_get_thread_num());
            #pragma omp for
            for (int j = 0; j < N; j++) {
                printf("\t\t inner loop %d, thread num %d\n", j, omp_get_thread_num());
            }
        }
    }
}

int main() {
    loop(2,30);
}

パフォーマンスの観点から、このようにループを融合することを検討することをお勧めします。

#pragma omp for
for(int n=0; n<iterations*N; n++) {
    int i = n/N;
    int j = n%N;    
    //do something as function of index i and j
}
于 2013-05-08T10:12:09.753 に答える
0

コード内の依存関係に大きく依存するため、答えるのは困難です。しかし、これを解決する一般的な方法は、次のようにループのネストを逆にすることです。

#pragma omp parallel
{
    #pragma omp for
    for (int j = 0; j < N; j++) {
        for (int i = 0; i < iterations; i++) {
            // Do something
        }
    }
}

もちろん、ループ内のコードに応じて、これは可能または不可能です。

于 2013-05-08T13:14:06.583 に答える