此代码不会使代码更快地计算4个和。相反,它甚至需要更多时间。 输出也不是预期的。
#include <stdio.h>
#include <omp.h>
int main()
{
int i,j,k,l;
int sum = 0,sum1 = 0,sum2 = 0,sum3 = 0;
#pragma omp parallel
{
#pragma omp sections
{
#pragma omp section
{
printf("%d",omp_get_thread_num());
for(i = 0; i < 500000000; i++) sum = sum + 1;
}
#pragma omp section
{
printf("%d",omp_get_thread_num());
for(i = 0; i < 500000000; i++) sum1 = sum1 + 1;
}
#pragma omp section
{
printf("%d",omp_get_thread_num());
for(i = 0; i < 500000000; i++) sum2 = sum2 + 1;
}
#pragma omp section
{
printf("%d",omp_get_thread_num());
for(i = 0; i < 500000000; i++) sum3 = sum3 + 1;
}
}
}
printf("sum is %d %d %d %d", sum,sum1,sum2,sum3);
}
输出为sum is 218748707 222052401 239009041 196849489
让我知道在这里使用openmp的缺陷。
答案 0 :(得分:5)
减速源于sum
,sum1
,sum2
和sum3
是共享变量的事实,因此编译器必须生成获取/更新/存储指令每个增量而不是像寄存器一样只保留寄存器中的中间和。
你应该使用它所使用的线程的每个和。最简单的方法是减少每个总和:
#pragma omp parallel private(i) reduction(+:sum,sum1,sum2,sum3)
{
// Rest of the code goes unchanged
}
private(i)
将解决问题,但结果不正确。 reduction(+:sum,sum1,sum2,sum3)
会使每个帖子累积自己的sum
,sum1
,sum2
和sum3
副本,最后将本地副本添加到表单中最后的价值观。
以下是一些表现数据:
串行版 - 3.812秒:
$ gcc -o mp.x mp.c -lgomp
$ time ./mp.x
0000sum is 500000000 500000000 500000000 500000000
./mp.x 3.81s user 0.00s system 99% cpu 3.812 total
带共享变量的OpenMP版本 - 7.982秒:
$ gcc -fopenmp -o mp.x mp.c
$ time OMP_NUM_THREADS=4 ./mp.x
0132sum is 500000000 500000000 500000000 500000000
OMP_NUM_THREADS=4 ./mp.x 21.88s user 0.86s system 284% cpu 7.982 total
OpenMP版本减少 - 1.226秒:
$ gcc -fopenmp -o mp.x mp.c
$ time OMP_NUM_THREADS=4 ./mp.x
0321sum is 500000000 500000000 500000000 500000000
OMP_NUM_THREADS=4 ./mp.x 4.53s user 0.00s system 370% cpu 1.226 total
另外还有另一个代码转换会降低速度,而sum
,sum1
,sum2
和sum3
位于堆栈上主程序,而部分代码由OpenMP处理器提取并放入单独的函数,然后由并行团队中的每个线程调用。该函数提供了一个数据结构,其中包含指向四个共享和的指针,并且代码与这些指针一起操作。您可以在两种情况下比较汇编器输出并亲自查看 - 如果您想深入了解并行性能,那么这样做非常有启发性。
答案 1 :(得分:3)
使用并发并不总是免费的。可能存在您未看到的开销,例如创建新线程,锁定内存区域等。你无法总是期望通过琐碎的任务提升性能。
您没有获得预期输出的原因是因为所有线程都使用相同的循环变量(i
)。这会导致数据争用,这也是您的总和不超过500000000的原因。