Range-v3 视图组合和视图计算并行化

问题描述

取自 range-v3 文档,以下示例演示了 views 的简单组合,通过流水线生成 range

std::vector<int> const vi{1,2,3,4,5,6,7,8,9,10};
using namespace ranges;
auto rng = vi | views::remove_if([](int i){return i % 2 == 1;})
              | views::transform([](int i){return std::to_string(i);});

我知道 views::foo 等价于 foo_view() 之类的东西,因此上面的例子最终是这样的:

transform_view(remove_if_view(vi,<lambda>),<lambda>)

现在的问题是:

remove_iftransform 操作的顺序是如何发生的? (我知道它们是懒惰的,它们实际上并没有在这一步计算,而不是在 rng 实现时计算,但这不是重点

我可以在这里看到两个选项:

  1. 这些操作由 range-v3 融合,当 rng 的给定元素通过某个迭代器访问时,这两个操作因此应用于该元素。 >

  2. 当请求给定元素时,整个 remove_if 操作会应用于整个 vi,然后该操作的输出向量被送入 transform。因此,我们最终得到了一个完整的“trasformed + removed_if”向量,它使我们能够访问所需的元素。

我很确定选项 (1) 是实际发生的情况。如果是这种情况,range-v3 是如何实现的?它是否有某种通用组合代码来组合无限数量的组合视图操作?

附带问题:range-v3 视图公开什么样的迭代器?我认为 random-access 迭代器下面的任何内容都会使并行化变得不可能。

元问题:如果选项 (1) 是事实,那么并行化 range-algorithms 是不是非常简单,因为它们将一个简单的范围(由多个视图组成,按需计算)作为输入操作融合)?

解决方法

如果我不得不猜测,那么我会说 | 运算符构建了一个编译时 AST(抽象语法树)操作。如果将此 AST 存储到名为 range 的变量中,然后调用 auto it = std::begin(range),则您将实现一个迭代器,该迭代器的类型将非常重要(除非使用类型擦除)。当您调用 *it 时,它会评估从取消引用原始迭代器的当前状态开始的所有转换操作。当您调用 ++it 时,它有点复杂。它需要做几件事。它需要推进基本迭代器,但它还需要评估所有中间转换,以便可以评估 remove_if 中的谓词。如果谓词返回 true,则基迭代器需要再次前进,因为我们正在跳过一个项目。

如果您将 transform 放在 remove_if 之前,这可能会导致管道效率低下。对于每个项目,转换将被评估两次。一次用于推进迭代器,第二次用于读取当前值。如果转换不是微不足道的,那么你会减速。如果转换有副作用,那么可能会发生不好的事情。见

Why C++ ranges "transform -> filter" calls transform twice for values that match the filter's predicate?

了解更多详情

关于使操作并行,它可能类似于 std 库实现,通过向每个 AST 节点添加一个标签参数来说明您是否要并行执行。有关详细信息,请参阅https://www.modernescpp.com/index.php/parallel-algorithm-of-the-standard-template-library

例如

vector<int> v = ...

// standard sequential sort
std::sort(v.begin(),v.end());

// sequential execution
std::sort(std::parallel::seq,v.begin(),v.end());

// permitting parallel execution
std::sort(std::parallel::par,v.end());

// permitting parallel and vectorized execution
std::sort(std::parallel::par_unseq,v.end());

这种模式可以扩展到 range-v3,但本质上重载将是新的实现并且实现起来并不容易。

rangev3 github 页面中有一个关于此主题的未解决问题,其中包含一些您可能感兴趣的进一步链接。

https://github.com/ericniebler/range-v3/issues/921

(我不是 range-v3 的贡献者,但我已经实现了我自己的 range like library,它在功能上与 range-v3 有重叠。)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...