通过以下示例,您将能够更好地理解这一点。让我们用两个线程来做这件事。
#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
这意味着,当您将 #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
为了明智地并行化代码组合,我们可以添加折叠关键字,如下所示。
#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 and j=2 threadId=1) 也 (i=1 and j=0 threadId=0))。这意味着在这种情况下,i 和 j 的组合在线程之间进行划分。