2

此代码不会使计算 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 的缺陷。

4

2 回答 2

5

减速源于这样一个事实,即,sum和是共享变量,因此编译器必须为每个增量生成获取/更新/存储指令,而不是像串行版本那样仅将中间和保存在寄存器中。sum1sum2sum3

您应该将每个总和设置为使用它的线程的本地。最简单的方法是减少每个总和:

#pragma omp parallel private(i) reduction(+:sum,sum1,sum2,sum3)
{
    // Rest of the code goes unchanged
}

private(i)将解决结果不正确的问题。reduction(+:sum,sum1,sum2,sum3)将使每个线程累积自己的、和副本sum,最后本地副本将相加形成最终值。sum1sum2sum3

以下是一些性能数据:

串行版本 - 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和位于主程序的堆栈上,而部分代码由 OpenMP 处理器提取并放入单独的函数中,然后由并行团队中的每个线程。该函数提供了一个数据结构,其中包含指向四个共享和的指针,并且代码使用这些指针进行操作。您可以比较两种情况下的汇编程序输出并亲自查看 - 如果您想更深入地研究并行性能的东西,这样做非常有指导意义。sum1sum2sum3

于 2012-06-18T08:41:21.943 回答
3

使用并发并不总是免费的。可能会涉及到您看不到的开销,例如创建新线程、锁定内存区域等。您不能总是期望琐碎任务的性能提升。

您没有得到预期输出的原因是因为所有线程都使用相同的循环变量 ( i)。这会导致数据竞争,这也是您的总和不等于 500000000 的原因。

于 2012-06-18T06:20:43.473 回答