56

次のコードは、最初の(外部)ループを並列化するだけですか、それともネストされたループ全体を並列化しますか?

    #pragma omp parallel for
    for (int i=0;i<N;i++)
    { 
      for (int j=0;j<M;j++)
      {
       //do task(i,j)//
      }
    }

上記のコードがネストされたforループ全体を並列化するか(したがって、1つのスレッドがtask(i、j)に直接関連する)、または外側のforループのみを並列化するか(したがって、各並列に対して確実になります)を確認したいだけです。ループインデックスがiのスレッドの場合、その内部ループは単一のスレッドで順次実行されます。これは非常に重要です)。

4

2 に答える 2

68

あなたが書いた行は、外側のループだけを並列化します。collapse両方を並列化するには、句を追加する必要があります。

#pragma omp parallel for collapse(2)
    for (int i=0;i<N;i++)
    { 
      for (int j=0;j<M;j++)
      {
       //do task(i,j)//
      }
    }

詳細については、OpenMP 3.1の仕様(2.5.1秒)を確認することをお勧めします。

于 2012-11-13T07:51:37.103 に答える
25

次の例を使用すると、これをよりよく理解できるようになります。これを2つのスレッドで実行しましょう。

#pragma omp parallel for num_threads(2)
for(int i=0; i< 3; i++) {
    for (int j=0; j< 3; j++) {
        printf("i = %d, j= %d, threadId = %d \n", i, j, omp_get_thread_num());
    }
}

その結果、次のようになります。

i = 0, j= 0, threadId = 0 
i = 0, j= 1, threadId = 0 
i = 0, j= 2, threadId = 0 
i = 1, j= 0, threadId = 0 
i = 1, j= 1, threadId = 0 
i = 1, j= 2, threadId = 0 
i = 2, j= 0, threadId = 1 
i = 2, j= 1, threadId = 1 
i = 2, j= 2, threadId = 1

つまり、最上位のforループに#pragma omp parallel forを追加すると、そのforループのインデックスがスレッド間で分割されます。ご覧のとおり、iのインデックスが同じ場合、スレッドIDも同じです。

その代わりに、ネストされたforループにある組み合わせを並列化できます。この例では、iとjの次の組み合わせを持つことができます。

i = 0, j= 0
i = 0, j= 1
i = 0, j= 2
i = 1, j= 0
i = 1, j= 1
i = 1, j= 2
i = 2, j= 0
i = 2, j= 1
i = 2, j= 2

コードの組み合わせを賢く並列化するために、次のようにcollapseキーワードを追加できます。

#pragma omp parallel for num_threads(2) collapse(2)
for(int i=0; i< 3; i++) {
    for (int j=0; j< 3; j++) {
        printf("i = %d, j= %d, threadId = %d \n", i, j, omp_get_thread_num());
    }
}

その場合、結果は次のようになります。

i = 0, j= 0, threadId = 0 
i = 0, j= 1, threadId = 0 
i = 1, j= 2, threadId = 1 
i = 2, j= 0, threadId = 1 
i = 2, j= 1, threadId = 1 
i = 2, j= 2, threadId = 1 
i = 0, j= 2, threadId = 0 
i = 1, j= 0, threadId = 0 
i = 1, j= 1, threadId = 0 

次に、以前とは異なり、同じインデックスiに対して、異なるスレッドIDが存在する可能性があることがわかります((i=1およびj=2 threadId = 1)の場合(i=1およびj=0 threadId = 0))。つまり、このシナリオでは、iとjの組み合わせがスレッド間で分割されます。

于 2018-05-22T10:36:25.183 に答える