Openmp并行不起作用

时间:2013-08-06 07:32:21

标签: openmp

我现在正在学习OpenMP,我有一个问题。虽然所有线程都在访问该函数,但以下代码的工作时间和没有并行部分的相同代码在统计上是相等的。我试着看一下互联网上的一些指南,但它没有帮助。所以问题是,这个并行部分出了什么问题?

int sumArrayParallel( )
{

    int i = 0;
    int sum = 0;
    #pragma omp parallel for
    for (i = 0; i < arraySize; ++i)
    {
        cout << omp_get_thread_num() << " ";
        sum += testArray[i];
    }
    return sum;
}

1 个答案:

答案 0 :(得分:4)

有两个非常常见的原因导致OpenMP代码无法表现出比串行代码更高的性能:

  1. 正在完成的工作不足以超过并行计算的开销。可以想象,建立一个线程团队,为他们分配工作,收集他们的结果需要花费时间。除非这个成本低于通过并行计算节省的时间,否则OpenMP代码即使是正确的,也不会显示任何加速,并且可能显示相反的情况。你没有向我们展示数字,所以你自己做计算。

  2. 程序员对并行程序进行串行操作,可能是通过将数据访问包含在内存中,也许是通过访问本质上串行的平台资源。我怀疑(但我对C的了解很糟糕),你对cout的写作可能会无意中将你的计算部分序列化。

  3. 当然,你可能会混淆这两个问题,过多的序列化和不够的工作,导致表现令人失望。

    进一步阅读this page on Intel's website非常有用,而且不仅适用于初学者。

    但我认为,您的代码问题比其糟糕的并行性能更严重。 OpenMP版本是否生成正确的sum?由于您没有制定任何特定条款sum由所有线程共享,它们将竞争以便访问它。学习OpenMP时,最好将条款default(none)附加到并行区域,并负责定义每个区域中每个变量的共享/私有状态。然后,一旦熟练掌握OpenMP,您就会知道为什么继续使用default(none)子句是有意义的。

    即使您回复是,代码也会生成正确的结果数据竞争存在且您的程序无法信任。这样的数据竞赛很有趣,它们不会出现在你运行的所有测试中,一旦你将你的代码推广到生产环境中, bang!并且整个蛋都在你的脸上。

    但是,您似乎正在推动自己的reduction,OpenMP提供了执行此操作的工具。调查OpenMP参考中的reduction子句。如果我正确地阅读了您的代码,并考虑了上面的建议,您可以将循环重写为

    #pragma omp parallel for default(none) shared(sum, arraySize, testArray) private(i) reduction(+:sum)
    for (i = 0; i < arraySize; ++i)
    {
        sum += testArray[i];
    }
    

    简而言之,使用reduction子句告诉OpenMP解决从跨线程分布的工作中汇总单个值的问题,避免竞争条件

    由于OpenMP默认情况下将循环迭代变量设为私有,因此可以省略指令中的private(i)子句,而不会有太大的风险。更好的方法可能是在for语句中声明它:

    #pragma omp parallel for default(none) shared(sum, arraySize, testArray) reduction(+:sum)
    for (int i = 0; i < arraySize; ++i)
    

    在并行区域内声明的变量(除了一些特殊情况)总是私有的。