如何将 openmp 缩减与二维向量一起使用

How to use openmp reduction with two dimensional vector

我想用 openmp 在 C++ 中并行化这个 for 循环:

   #pragma omp parallel for reduction(+:A)
   for (uint k = 0; k < nInd; ++k)
        {
            for (uint l = k; l < nInd; ++l)
            {
                    A.at(k).at(l) = A.at(k).at(l) + frq.at(l);
                    A.at(l).at(k) = A.at(k).at(l);        
            }
        }

但是 openmp 不知道如何添加 Astd::vector<std::vector<float>>.

我该如何解决这个问题?

错误是: 找不到“A”的用户定义缩减

关于这个错误我不能告诉你太多,我可以告诉你你正在做的不是你应该做的:

在这里使用 bounds-checking A.at(i).at(j) 而不是原始 A[i][j] 是一个坏主意:你知道长度在这个循环的入口处保持不变,所以只需检查长度一次,然后使用更快的[]。这尤其糟糕,因为使用 at,openmp 可能不得不采取不必要的预防措施(multi-threaded 代码中的异常总是有点……特殊),并且您可以并发读取向量长度一直而不是独立访问原始内存。然而,最重要的是:

内部循环更改 l。排。这意味着内循环处理的行的顺序很重要!这意味着您不能接受并行化。如果允许 openmp 完全并行化行上的操作,这将不可避免地导致其他线程访问内存的情况,单个线程仍然 read-accessing.

我没有看到这个循环的好的解决方案。也许您想从中创建两个循环:一个只添加 frq 值,一个转置您的矩阵。或者,写入一个单独的矩阵,而不是在 A 中执行此操作 in-place(这是否有效是内存大小的问题)。

我的一般建议是您永远不要实际转置矩阵(除非您确实需要确保内存访问模式);那只是浪费 CPU。无论使用什么转置矩阵,都可以在没有额外计算成本的情况下交换其行和列索引,并且您可以“免费”获得转置。

另一个建议:有很好的线性代数 C++ 库。使用它们。 You get well-parallelized (-able) functions,通常还有 views 之类的数据,其中转置只是改变寻址的方式(即,基本上是免费的)。

std::vector<std::vector<float>> 意味着每个元素访问要执行 两个 内存间接寻址,这相对昂贵。 CPU 将两个浮点数相乘所需的时间比从尚未在缓存中的内存中获取地址所需的时间少得多 – 因此,你 真的 想要你的完整的矩阵在一块连续的内存中,而不是分布在周围。如果您有 openmp 的用例,那么您将投入大量精力来使您的代码 运行 更快。与其先做困难的事情(并行化),不如先使用更好的方法通过 std::vector<std::vector<float>> 表示矩阵,然后使用 .at(i).at(j).

访问它们