命名空间
变体
操作

std::experimental::parallel::reduce

来自 cppreference.cn
定义于头文件 <experimental/numeric>
template< class InputIt >

typename std::iterator_traits<InputIt>::value_type reduce(

    InputIt first, InputIt last );
(1) (并行性 TS)
template< class ExecutionPolicy, class InputIterator >

typename std::iterator_traits<InputIt>::value_type reduce(

    ExecutionPolicy&& policy, InputIt first, InputIt last );
(2) (并行性 TS)
template< class InputIt, class T >
T reduce( InputIt first, InputIt last, T init );
(3) (并行性 TS)
template< class ExecutionPolicy, class InputIt, class T >
T reduce( ExecutionPolicy&& policy, InputIt first, InputIt last, T init );
(4) (并行性 TS)
template< class InputIt, class T, class BinaryOp >
T reduce( InputIt first, InputIt last, T init, BinaryOp binary_op );
(5) (并行性 TS)
template< class ExecutionPolicy, class InputIt, class T, class BinaryOp >

T reduce( ExecutionPolicy&& policy,

          InputIt first, InputIt last, T init, BinaryOp binary_op );
(6) (并行性 TS)
1)reduce(first, last, typename std::iterator_traits<InputIt>::value_type{}) 相同。
3)reduce(first, last, init, std::plus<>()) 相同。
5) 归约范围 [firstlast),可能以未指定的方式排列和聚合,连同初始值 init 通过 binary_op
2,4,6)(1,3,5) 相同,但根据 policy 执行。

如果 binary_op 不满足结合律或交换律,则行为是不确定的。

如果 binary_op 修改了范围 [firstlast) 中的任何元素或使任何迭代器失效,则行为是未定义的。

目录

[编辑] 参数

first, last - 应用算法的元素范围
init - 广义和的初始值
policy - 执行策略
binary_op - 二元函数对象,它将以未指定的顺序应用于解引用输入迭代器的结果、其他 binary_op 的结果和 init
类型要求
-
InputIt 必须满足 LegacyInputIterator 的要求。

[编辑] 返回值

init*first, *(first + 1), ... *(last - 1) 通过 binary_op 的广义和,

其中广义和 GSUM(op, a1, ..., aN) 定义如下

  • 如果 N=1, a1
  • 如果 N > 1, op(GSUM(op, b1, ..., bK), GSUM(op, bM, ..., bN)) 其中
  • b1, ..., bN 可以是 a1, ..., aN 的任何排列,并且
  • 1 < K+1 = M ≤ N

换句话说,范围内的元素可以任意顺序分组和重排。

[编辑] 复杂度

O(last - first)binary_op 的应用。

[编辑] 异常

  • 如果在算法执行过程中调用的函数抛出异常,
  • 如果 policyparallel_vector_execution_policy,则调用 std::terminate
  • 如果 policysequential_execution_policyparallel_execution_policy,则算法退出并返回一个 exception_list,其中包含所有未捕获的异常。如果只有一个未捕获的异常,算法可能会重新抛出它,而无需包装在 exception_list 中。在遇到第一个异常后,算法在返回之前将执行多少工作是未指定的。
  • 如果 policy 是其他类型,则行为是实现定义的。
  • 如果算法无法分配内存(无论是为了自身还是在处理用户异常时构造 exception_list),则抛出 std::bad_alloc

[编辑] 注解

如果范围为空,则返回 init,不进行修改。

  • 如果 policysequential_execution_policy 的实例,则所有操作都在调用线程中执行。
  • 如果 policyparallel_execution_policy 的实例,则操作可能在未指定数量的线程中执行,彼此之间以不确定的顺序排序。
  • 如果 policyparallel_vector_execution_policy 的实例,则执行可能是并行化和向量化的:函数体边界不受尊重,用户代码可能以任意方式重叠和组合(特别是,这意味着用户提供的 Callable 不得获取互斥锁来访问共享资源)。

[编辑] 示例

reduce 是 std::accumulate 的乱序版本

#include <chrono>
#include <experimental/execution_policy>
#include <experimental/numeric>
#include <iostream>
#include <numeric>
#include <vector>
 
int main()
{
    std::vector<double> v(10'000'007, 0.5);
 
    {
        auto t1 = std::chrono::high_resolution_clock::now();
        double result = std::accumulate(v.begin(), v.end(), 0.0);
        auto t2 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> ms = t2 - t1;
        std::cout << std::fixed << "std::accumulate result " << result
                  << " took " << ms.count() << " ms\n";
    }
 
    {
        auto t1 = std::chrono::high_resolution_clock::now();
        double result = std::experimental::parallel::reduce(
                            std::experimental::parallel::par,
                            v.begin(), v.end());
        auto t2 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> ms = t2 - t1;
        std::cout << "parallel::reduce result "
                  << result << " took " << ms.count() << " ms\n";
    }
}

可能的输出

std::accumulate result 5000003.50000 took 12.7365 ms
parallel::reduce result 5000003.50000 took 5.06423 ms

[编辑] 参见

对元素范围求和或折叠
(函数模板) [编辑]
将函数应用于元素范围,并将结果存储在目标范围中
(函数模板) [编辑]
(并行性 TS)
应用函子,然后乱序归约
(函数模板) [编辑]