当我在两台不同的机器上运行下面的代码时,我得到不同的输出,其中一台的输出是正确的(sum = sum2),而另一台则不是。
我不知道为什么
#include <stdio.h>
#include <math.h>
#include <omp.h>
int main(){
const int NX=1000;
const int NY=1000;
float x[NX+2];
float y[NX+2];
float u[NX+2][NY+2];
float x2; //
float y2;
float sum;
float sum2;
for (int i=0; i<NX+2; i++){
for (int j=0; j<NY+2; j++){
x2 = i;
y2 = j;
u[i][j] = x2+ y2;
sum += u[i][j];
}
}
for (int i=0; i<NX+2; i++){
#pragma omp parallel for
for (int j=0; j<NY+2; j++){
x2 = i;
y2 = j;
u[i][j] = x2+ y2;
}
}
for (int i=0; i<NX+2;i++){
for (int j=0; j<NY+2; j++){
sum2 += u[i][j];
}
}
printf("%f n", sum);
printf("%f", sum2);
}
您需要初始化
的值float sum;
float sum2;
sum += u[i][j];
和
sum2 += u[i][j];
导致未定义的行为。这就是为什么你会看到两个不同的结果
设置两个变量为零:
float sum = 0;
float sum2 = 0;
用(至少)-Wall标志编译你的代码。如果您这样做了,您将看到以下警告:
main.c:17:7: warning: 'sum2' may be used uninitialized in this function [-Wmaybe-uninitialized]
17 | float sum2;
| ^~~~
main.c:16:7: warning: 'sum' may be used uninitialized in this function [-Wmaybe-uninitialized]
16 | float sum;
| ^~~
性能方面,而不是并行的内部循环:
for (int i=0; i<NX+2; i++){
#pragma omp parallel for
for (int j=0; j<NY+2; j++){
x2 = i;
y2 = j;
u[i][j] = x2+ y2;
}
}
您应该通过使用OpenMP折叠选项来分析并行两个循环时会发生什么
#pragma omp parallel for collapse(2)
for (int i=0; i<NX+2; i++){
for (int j=0; j<NY+2; j++){
u[i][j] = i + j;
}
}
即使collapse
条款不是意见(例如:(比较慢),但在性能方面,并行化外部循环比并行化内部循环更好。首先,您可以避免多次创建并行区域NX+2
的开销。其次,由于外部循环遍历列,而内部循环遍历行,因此在线程之间划分第一个循环的迭代减少了错误共享的可能性。
此外,您还可以并行化其他两个循环。但是,您需要使用OpenMP缩减子句来避免在sum和sum2变量更新期间出现竞争条件。
最终代码如下所示:
#include <stdio.h>
#include <math.h>
#include <omp.h>
int main(){
const int NX=1000;
const int NY=1000;
float u[NX+2][NY+2];
float sum = 0;
float sum2 = 0;
#pragma omp parallel for reduction(+:sum)
for (int i=0; i<NX+2; i++){
for (int j=0; j<NY+2; j++){
sum += i+j;
}
}
#pragma omp parallel for
for (int i=0; i<NX+2; i++){
for (int j=0; j<NY+2; j++){
u[i][j] = i+j;
}
}
#pragma omp parallel for reduction(+:sum2)
for (int i=0; i<NX+2;i++){
for (int j=0; j<NY+2; j++){
sum2 += u[i][j];
}
}
printf("%f n", sum);
printf("%f", sum2);
}