Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ OpenMP如何处理嵌套循环?_C++_Loops_Parallel Processing_Openmp - Fatal编程技术网

C++ OpenMP如何处理嵌套循环?

C++ OpenMP如何处理嵌套循环?,c++,loops,parallel-processing,openmp,C++,Loops,Parallel Processing,Openmp,下面的代码只是并行化了第一个(外部)循环,还是并行化了整个嵌套循环 #pragma omp parallel for for (int i=0;i<N;i++) { for (int j=0;j<M;j++) { //do task(i,j)// } } #pragma omp parallel for 对于(int i=0;i您所写的行将仅并行化外部循环。要并行化两者,您需要添加一个collaps

下面的代码只是并行化了第一个(外部)循环,还是并行化了整个嵌套循环

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

对于(int i=0;i您所写的行将仅并行化外部循环。要并行化两者,您需要添加一个
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)//
      }
    }
用于折叠的pragma omp并行(2)
for(int i=0;iOpenMP只对pragma旁边的循环进行并行化。如果您愿意,也可以对内部循环进行并行化,但不会自动进行。通过以下示例,您将能够更好地理解这一点。 让我们用两个线程来完成这个任务

#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());
    }
}
这意味着,当您将#pragma omp parallel for添加到最上面的for循环时,for循环的索引将在线程之间划分。如您所见,当i的索引相同时,线程id也相同

相反,我们可以并行嵌套for循环中的组合

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的组合在线程中被划分。

谢谢,那太好了,我只想并行外部循环,同时确保内部循环按顺序工作。在这种情况下,我需要将
i
j
声明为私有吗?@giannis gonidelis,不,你不需要。我被告知这是很好的做法ce这样做,但我个人不喜欢这样做,因为不将I和j声明为私有更容易/更简单。正确嵌套循环后,外循环并行化通常是最好的。如果外循环计数与线程数相比不太大,如果可以使嵌套循环合格,并且它不会干扰内部循环优化,如simd矢量化。由于数据依赖性,并非所有循环都可以折叠,因此通常的答案是否定的,因为嵌套并行并不适用于每个循环,这就是为什么人们更多地转向GPU的原因,GPU有三个级别的并行
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