std::experimental::parallel::reduce

来自cppreference.com
在标头 <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),可能以未指明的方式,在 binary_op 上同初值 init 一起进行排列和聚合。
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, a
1
, ..., a
N
)
定义如下:

  • 如果 N=1,则 a
    1
  • 如果 N > 1,则 op(GSUM(op, b
    1
    , ..., b
    K
    ), GSUM(op, b
    M
    , ..., b
    N
    ))
    其中
  • b
    1
    , ..., b
    N
    可能是 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

参阅

对一个范围内的元素求和或折叠
(函数模板)
将一个函数应用于某一范围的各个元素,并在目标范围存储结果
(函数模板)
应用函数对象,然后进行不按顺序的规约
(函数模板)