【问题标题】:Parallelizing a simple loop with c++17 algorithms用 c++17 算法并行化一个简单的循环
【发布时间】:2019-06-28 12:59:57
【问题描述】:

我有一个并行代码,基本上可以简化为:

#include <algorithm>
#include <vector>

struct TKeyObjPtr;

class TObj
{
public:
  virtual void Calculate(TKeyObjPtr const &) = 0;
};

struct TKeyObjPtr
{
  int Key;
  TObj *ObjPtr;
};

void Calculate(std::vector<TKeyObjPtr> const &KeyObjPtrVec)
{
  #pragma omp parallel for
  for (auto It1= KeyObjPtrVec.begin(); It1!=KeyObjPtrVec.end(); ++It1)
    for (auto It2= It1+1; It2!=KeyObjPtrVec.end() && It2->Key==It1->Key; ++It2)
      It1->ObjPtr->Calculate(*It2);
}

我想通过使用 并行算法对代码进行现代化改造。 不幸的是,我在重写这么简单的一段代码时遇到了麻烦。

一个选项是使用boost::counting_iterator:

void Calculate(std::vector<TKeyObjPtr> const &KeyObjPtrVec)
{
  std::for_each(std::execution::par_unseq,
    boost::counting_iterator<std::size_t>(0u),
    boost::counting_iterator<std::size_t>(KeyObjPtrVec.size()),
    [&KeyObjPtrVec](auto i)
      {
        for (auto j= i+1; j<KeyObjPtrVec.size() && KeyObjPtrVec[j].Key==KeyObjPtrVec[i].Key; ++j)
          KeyObjPtrVec[i].ObjPtr->Calculate(KeyObjPtrVec[j]);
      });
}

这可行,但更冗长,更糟糕的是,我认为它不符合 标准,因为 boost::counting_iterator 是一个存储迭代器,因此不 见Cpp17ForwardIterator requirements

是否可以像使用 OpenMP 一样简洁地编写上述代码,同时满足 标准对并行算法的限制?

【问题讨论】:

  • 你确定counting_iterator 不是ForwardIterator 吗? Afaik ForwardIterator 只是使for_each 工作所需的最低要求,而不是更多
  • @user463035818 问题是 ForwardIterator 需要返回对某个对象的引用。 counting_iterator 按值返回。
  • @metalfox 这不是我在您链接的文档中看到的。我看到reference typedef 是const Incrementable&amp;,而operator* 确实返回reference
  • 我不认为这个循环符合“简单”的条件。 It1-&gt;ObjPtr-&gt;Calculate(*It2); 中的迭代器配对源于比较相等的连续 Key 值,但仅在 It1 尚未通过的容器部分中,加上迭代器后面的对象配对将多次使用超过两个相等连续键。

标签: c++17 c++ iterator c++17 stl-algorithm


【解决方案1】:

迭代器可以按值赋值。分配的迭代器是一个副本,当原始分配源增加时不会前进。因此,您可以简单地

template<typename I>
void calculate(const I It1, const I It2) {
  // This statement can also run at any time later. The iterators will point
  // how they were when the calculate(...) was called.
  It1->ObjPtr->Calculate(*It2); 
}

void Calculate(std::vector<TKeyObjPtr> const &KeyObjPtrVec) {
  for (auto It1 = KeyObjPtrVec.begin(); It1 != KeyObjPtrVec.end(); ++It1)
    for (auto It2 = It1 + 1; It2 != KeyObjPtrVec.end() && 
      It2->Key == It1->Key; ++It2)
        calculate(It1, It2);
}

很遗憾,C++17 并不是这样一个专用的并行编程平台。您需要安排一个有意义大小的线程池和任务队列,他们可以从中挑选任务。任务记录可以只保存这两个分配为结构字段的迭代器。您还需要一种机制来了解所有并行处理何时完成,以便您可以继续。

【讨论】:

    猜你喜欢
    • 2012-04-04
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    • 2021-12-20
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多