use*_*128 31 c++ parallel-processing loops openmp
以下代码是仅仅并行化第一个(外部)循环,还是并行化整个嵌套循环?
#pragma omp parallel for
for (int i=0;i<N;i++)
{
for (int j=0;j<M;j++)
{
//do task(i,j)//
}
}
Run Code Online (Sandbox Code Playgroud)
我只是想确定上面的代码是否会并行化整个嵌套的for循环(因此一个线程直接相关的任务(i,j)),或者它只是并行化外部for循环(因此它确保了每个并行)带有循环索引i的线程,它的内部循环将在一个线程中顺序完成,这非常重要).
Mas*_*ano 44
您编写的行将仅与外部循环并行化.要并行化两者,您需要添加一个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)//
}
}
Run Code Online (Sandbox Code Playgroud)
您可能需要查看OpenMP 3.1规范(第2.5.1节)以获取更多详细信息.
小智 8
您将能够通过以下示例更好地理解这一点.让我们用两个线程做到这一点.
#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());
}
}
Run Code Online (Sandbox Code Playgroud)
然后结果将是,
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
Run Code Online (Sandbox Code Playgroud)
这意味着,当您将#pragma omp parallel for添加到最上面的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
Run Code Online (Sandbox Code Playgroud)
为了明确地并行化代码组合,我们可以按如下方式添加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());
}
}
Run Code Online (Sandbox Code Playgroud)
那么结果将如下.
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
Run Code Online (Sandbox Code Playgroud)
然后你可以看到,与以前不同,对于相同的索引i,可以有不同的线程id(当(i = 1且j = 2 threadId = 1)时(i = 1且j = 0 threadId = 0)).这意味着在这种情况下,i和j的组合在线程之间划分.