您的代码的问题在于内部循环的迭代取决于外部循环。根据OpenMP规范下有关绑定部分的描述以及collapse
clause:
如果任何关联循环的执行改变了用于计算任何值的任何值
迭代计数,则行为未指定。
当情况并非如此时,您可以使用折叠,例如使用方形循环
#pragma omp parallel for private(j) collapse(2)
for (i = 0; i < 4; i++)
for (j = 0; j < 100; j++)
事实上,这是一个很好的例子来展示何时使用折叠。外循环只有四次迭代。如果你有四个以上的线程,那么有些线程就会被浪费。但是,当您折叠时,线程将分布在 400 次迭代中,这可能比线程数大得多。使用塌陷的另一个原因是载荷分布不均匀。如果您只使用了四次迭代,并且第四次迭代占用了其他线程等待的大部分时间。但如果使用 400 次迭代,负载可能会得到更好的分布。
您可以为上面的代码手动融合一个循环,如下所示
#pragma omp parallel for
for(int n=0; n<4*100; n++) {
int i = n/100; int j=n%100;
Here https://stackoverflow.com/questions/18749493/openmp-drastically-slows-down-for-loop/18763554#18763554是一个示例,展示了如何手动熔合三重熔合环。
最后,here https://stackoverflow.com/questions/24013832/fusing-a-triangle-loop-for-parallelization-calculating-sub-indices是一个示例,显示如何融合三角形环collapse
没有定义。
这是一个将 OP 问题中的矩形循环映射到三角形循环的解决方案。这可用于融合 OP 三角环。
//int n = 4;
for(int k=0; k<n*(n+1)/2; k++) {
int i = k/(n+1), j = k%(n+1);
if(j>i) i = n - i -1, j = n - j;
printf("(%d,%d)\n", i,j);
}
这适用于任何 n 值。
OP问题的地图来自
(0,0),
(1,0), (1,1),
(2,0), (2,1), (2,2),
(3,0), (3,1), (3,2), (3,3),
to
(0,0), (3,3), (3,2), (3,1), (3,0),
(1,0), (1,1), (2,2), (2,1), (2,0),
对于 n 的奇数值,地图并不完全是矩形,但公式仍然有效。
例如 n = 3 映射自
(0,0),
(1,0), (1,1),
(2,0), (2,1), (2,2),
to
(0,0), (2,2), (2,1), (2,0),
(1,0), (1,1),
这是测试这个的代码
#include <stdio.h>
int main(void) {
int n = 4;
for(int i=0; i<n; i++) {
for(int j=0; j<=i; j++) {
printf("(%d,%d)\n", i,j);
}
}
puts("");
for(int k=0; k<n*(n+1)/2; k++) {
int i = k/(n+1), j = k%(n+1);
if(j>i) i = n - i - 1, j = n - j;
printf("(%d,%d)\n", i,j);
}
}