【问题标题】:Compute the minimum value of every row in a matrix using loops parallel with openmp C++使用与 openmp C++ 并行的循环计算矩阵中每一行的最小值
【发布时间】:2019-10-16 13:19:13
【问题描述】:

我想使用openmp c++​​并行计算矩阵中每一行的最小值,如下所示:

// matrix Distf (float) of size n by n is declared before. 
vector<float> minRows;
#pragma omp parallel for
for (i=0; i < n; ++i){
     float minValue = Distf[i][0];
     #pragma omp parallel for reduction(min : minValue)
     for (j=1; j < n; ++j){
          if (Distf[i][j] < minValue){
                    minValue = Distf[i][j];
           }
     }
     minRows.push_back(minValue);
 }

到目前为止,编译器没有引发任何错误,但我想知道这是否会像预期的那样给出正确的答案?谢谢

【问题讨论】:

  • 如果您提供了一个最小的工作示例,它会更容易提供帮助。也就是说,您是否尝试过检查?在我的最小示例中,即使是 3x3 矩阵也能给出非常明确的答案。
  • 为什么要并行化内循环?将外部并行化会简单得多。由于每次迭代(线程)处理不同的行,所以没有竞争,不需要减少,代码会更有效率。唯一的限制是您不能替换 push_back(),因为处理顺序是未定义的,并且必须通过在 minRows[i] 处的显式写入来替换它。
  • @AlainMerigot 内部循环由reduction(min: minValue) 表达式保护免受竞争条件的影响,如果我理解正确的话——openMP 似乎负责为每个任务创建本地副本。因此,尽管我同意矩阵必须很大,或者矩阵的元素比较昂贵,但这并不是一场数据竞赛。不过,push_back 是正确的。
  • @GeckoGeorge 我没有说有比赛,减少确保了正确的行为。我的意思是,如果在外循环上进行并行化,就不会发生任何竞争,这种结构不是必需的,每个线程都处理自己的数据,同步次数减少,并行化和性能将更好。
  • @GeckoGeorge 我已经检查了大小为 3.000 的实例,它工作正常。我必须使用“push_back”是有原因的。

标签: c++ loops parallel-processing openmp


【解决方案1】:

我们在 cmets 中谈到的作为答案:因为无论如何我都必须编写一些样板文件,所以我使用 int 作为类型并且完全避免考虑浮点问题:

#include <vector>
#include <iostream>

using namespace std;

int main(){
    constexpr size_t n = 3;
    // dummy Distf (int) declared in lieu of matrix Distf 
    int Distf[n][n] = {{1,2,3},{6,5,4},{7,8,8}};

    //could be an array<int,n> instead
    vector<int> minRows(n);
#pragma omp parallel for
    for (size_t i = 0; i < n; ++i){
        int minValue = Distf[i][0];
// Alain Merigot argues this is a performance drag
//#pragma omp parallel for reduction(min : minValue)
        for (size_t j = 1; j < n; ++j){
            if (Distf[i][j] < minValue){
                minValue = Distf[i][j];
            }
        }
        //minRows.push_back(minValue) is a race condition!
        minRows[i] = minValue;
    }

    int k = 0;
    for(auto el: minRows){
        cout << "row " << k++ << ": " << el << '\n';
    }
    cout << '\n';
}

内部循环通常不需要并行化。我不知道你可以使用多少个内核,但除非你在一个大规模并行系统上,想想 GPU 级别的并行性,外循环应该已经利用所有可用的内核,或者问题还不够大重要。在任何一种情况下启动更多线程都是一种悲观。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 2013-05-18
    • 2013-02-25
    • 2017-07-25
    • 2021-01-13
    相关资源
    最近更新 更多