我有将所有元素相互比较的简单问题。比较本身是对称的,因此,它不必进行两次。
以下代码示例通过显示所访问元素的索引来显示我要查找的内容:
int n = 5;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
printf("%d %d\n", i,j);
}
}
输出结果为:
0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
2 4
3 4
因此每个元素相互比较一次。当我想并行化这段代码时,我遇到的问题是首先我必须坚持动态调度,因为每次迭代的计算时间确实变化很大而且我不能使用崩溃,因为嵌套迭代是索引 - 依赖于外循环。
将#pragma omp parallel for schedule(dynamic, 3)
用于外部循环可能会导致最终的单核执行,而将内部循环用于内循环可能会导致在外循环的每次迭代中执行此类操作。
是否有更复杂的方法来进行/并行化?
答案 0 :(得分:2)
我还没有彻底考虑过,但你也可以尝试这样的方法:
int total = n * (n-1) / 2; // total number of combinations
#pragma omp parallel for
for (int k = 0; k < total; ++k) {
int i = first(k, n);
int j = second(k, n, i);
printf("%d %d\n", i,j);
}
int first(int k, int n) {
int i = 0;
for (; k >= n - 1; ++i) {
k -= n - 1;
n -= 1;
}
return i;
}
int second(int k, int n, int i) {
int t = i * (2*n - i - 1) / 2;
return (t == 0 ? k + i + 1 : (k % t) + i + 1);
}
答案 1 :(得分:0)
事实上,OpenMP标准表示崩溃:
在进入之前计算每个相关循环的迭代计数 到最外面的循环。如果任何相关循环的执行发生变化 然后,用于计算任何迭代计数的任何值 行为未指明。
所以你不能崩溃你的循环,这本来是最简单的方法。 但是,由于您对计算索引对的顺序不是特别感兴趣,因此您可以将循环更改为如下所示:
for ( int i = 0; i < n; i++ ) {
for ( int j = 0; j < n / 2; j++ ) {
int ii, jj;
if ( j < i ) {
ii = n - 1 - i;
jj = n - 1 - j;
}
else {
ii = i;
jj = j + 1;
}
printf( "%d %d\n", ii, jj );
}
}
这应该给你所有你想要的对,有点错误的顺序,但有固定的迭代限制,允许平衡的并行化,甚至循环崩溃,如果你想。简单地说,如果n是偶数,那么对应于n / 2的列将显示两次,因此您要么使用它,要么稍微修改算法以避免...
答案 2 :(得分:0)
我以前有以下好成绩:
#pragma omp parallel for collapse(2)
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (j <= i)
continue;
printf("%d %d\n", i, j);
}
}
请记住,printf
不会仅执行任何并行工作负载,因此最好是根据您的具体工作对其进行分析。您可以尝试添加schedule(dynamic, 10)
或大于10
的内容,具体取决于您执行的迭代次数。