在 std::vector 上的 Openmp 和缩减?

Posted

技术标签:

【中文标题】在 std::vector 上的 Openmp 和缩减?【英文标题】:Openmp and reduction on std::vector? 【发布时间】:2017-08-27 09:02:59 【问题描述】:

我想让这段代码并行:

std::vector<float> res(n,0);
std::vector<float> vals(m);
std::vector<float> indexes(m);
// fill indexes with values in range [0,n)
// fill vals and indexes
for(size_t i=0; i<m; i++)
  res[indexes[i]] += //something using vas[i];

在this 文章中建议使用:

#pragma omp parallel for reduction(+:myArray[:6])

在this 问题中,cmets 部分提出了相同的方法。

我有两个问题:

    在编译时我不知道m,从这两个例子看来这是必需的。是这样吗?或者,如果我可以在这种情况下使用它,我必须在以下命令 #pragma omp parallel for reduction(+:res[:?]) 中用什么替换 ?mn? for 的索引是否与indexesvals 相关而不是res,特别是考虑到reduction 是在后者上完成的?

但是,如果是这样,我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

对特定类型的 C++ 向量进行用户声明的缩减是相当直接的:

#include <algorithm>
#include <vector>

#pragma omp declare reduction(vec_float_plus : std::vector<float> : \
                              std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<float>())) \
                    initializer(omp_priv = decltype(omp_orig)(omp_orig.size()))

std::vector<float> res(n,0);
#pragma omp parallel for reduction(vec_float_plus : res)
for(size_t i=0; i<m; i++)
    res[...] += ...;

1a) 在编译时不知道m 不是必需的。

1b) 您不能在std::vectors 上使用数组部分缩减,因为它们不是数组(并且std::vector::data 不是标识符)。如果可能,您必须使用n,因为这是数组部分中的元素数。

2) 只要​​您只阅读indexesvals,就没有问题。

编辑:原来的 initializer 更简单:initializer(omp_priv = omp_orig)。但是,如果原始副本不全为零,则结果将是错误的。因此,我建议使用更复杂的初始化程序,它总是创建零元素向量。

【讨论】:

Omp 减少断言编译器不需要在重复间接索引的情况下处理数据重叠。 @time18 我不明白你的意思。你能详细说明一下吗?每个线程都有一个res 的私有副本,因此如果存在重复的间接索引也没有问题。 @Zulan 感谢您的回答。你能看看this吗? 如果我们先将vec的大小调整为n,然后像数组一样设置元素,不定义user-declared-reduction,这样会不会涉及false-sharing而降低性能?跨度> 只是想补充一点:在parallel 区域内使用它时要小心。然后,需要 scope 子句(目前还不太支持)或循环所有线程才能获得正确的结果。

以上是关于在 std::vector 上的 Openmp 和缩减?的主要内容,如果未能解决你的问题,请参考以下文章

C++:使用 OpenMP 插入 std::vector

C++ OpenMP 并行 For 循环 - std::vector 的替代品 [关闭]

OpenMP和不同的STL向量

如何使用 OpenMP 并行化最近邻搜索

OpenMP:如何在每个线程中利用递归函数?

用零并行填充 std::vector