(C++17) std算法之执行策略 execution

前言

ref:算法库-执行策略 - cppreference.com

利用多核cpu加速算法在目前看来已经不是什么新鲜事了。在C++17中,推出了算法函数的执行策略,可以选择执行策略来优化算法的执行效果。(注意不是所有算法都支持)

目前到C++20,已经支持了四种执行策略。当然本文也仅仅是做简单的展示和描述,因此内部细节十分复杂不是几篇端文章就能看懂的。

标准策略执行策略类型(类)全局执行策略对象(常量)
C++17串行执行sequenced_policystd::execution::seq
C++17并行执行parallel_policystd::execution::par
C++17并行无序执行parallel_unsequenced_policystd::execution::par_unseq
C++20无序执行unsequenced_policystd::execution::unseq
功能特性测试标准功能特性
__cpp_lib_parallel_algorithm201603LC++17并行算法
__cpp_lib_execution201603LC++17执行策略
__cpp_lib_execution201902LC++20std::execution::unsequenced_policy

Code测试

Code

这里仅展示一个比较简单的小例子,仅做小参考。

#include <algorithm>
#include <ctime>
#include <execution>
#include <iostream>
#include <string>
#include <vector>

 /**
  * 辅助计时类
  */
class Timer {
    std::string str;
    clock_t     start;

public:
    Timer(const std::string& str) : str(str) {
        start = clock();
    }

    ~Timer() {
        clock_t end = clock();
        std::cout << str << " => " << (end - start) / 1000.0 << '\n';
    }
};

/**
 * 串行执行策略
 * class sequenced_policy;
 */
void test_sequenced_policy(std::vector<int> arr) {
    Timer timer("std::execution::seq");
    std::sort(std::execution::seq, arr.begin(), arr.end());
}

/**
 * 并行执行策略
 * class parallel_policy;
 */
void test_parallel_policy(std::vector<int> arr) {
    Timer timer("std::execution::par");
    std::sort(std::execution::par, arr.begin(), arr.end());
}

/**
 * 并行无序执行策略
 * class parallel_unsequenced_policy;
 */
void test_parallel_unsequenced_policy(std::vector<int> arr) {
    Timer timer("std::execution::par_unseq");
    std::sort(std::execution::par_unseq, arr.begin(), arr.end());
}

/**
 * 无序执行策略
 * class unsequenced_policy;
 */
void test_unsequenced_policy(std::vector<int> arr) {
#if __cpp_lib_execution >= 201902L
    Timer timer("std::execution::unseq");
    std::sort(std::execution::unseq, arr.begin(), arr.end());
#endif
}

int main() {
    // help data
    std::vector<int> arr;
    for (int i = 0; i < 3.0 * 100'000'00; i += 1) {
        arr.push_back(rand());
    }

    test_sequenced_policy(arr);
    test_parallel_policy(arr);
    test_parallel_unsequenced_policy(arr);
    test_unsequenced_policy(arr);
}

运行效果

使用编译器:vs2019 => _MSC_VER = 1929

这只是基于笔者本地的单词测试,仅作参考。

x86-Debug

std::execution::seq => 22.874
std::execution::par => 5.495
std::execution::par_unseq => 5.854
std::execution::unseq => 22.864

x86-Release

std::execution::seq => 1.249
std::execution::par => 0.258
std::execution::par_unseq => 0.253
std::execution::unseq => 1.201

x64-Debug

std::execution::seq => 8.705
std::execution::par => 2.371
std::execution::par_unseq => 2.402
std::execution::unseq => 8.737

x64-Release

std::execution::seq => 1.179
std::execution::par => 0.25
std::execution::par_unseq => 0.238
std::execution::unseq => 1.129

msvc源码描述

std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy - cppreference.com

std::execution::seq, std::execution::par, std::execution::par_unseq, std::execution::unseq - cppreference.com

在以任何这些执行策略执行并行算法的过程中,若元素访问函数的调用因未捕获的异常退出,则调用 std::terminate,但实现可以定义以其他方式处理异常的额外执行策略。

源码

笔者看过gcc 11.2.0的实现,是用函数直接返回true-or-false的方式来区分。

但是注释基本没没什么描述,因此就不展示了。

本代码于msvc中<execution>

可见这里其实是定义了四个类型标签。标准没有定义对象内部的属性,这里是msvc的实现问题。

这里主要可以直接根据msvc的人话注释来理解标签的有含义。

namespace execution {
    class sequenced_policy {
        // indicates support for only sequential execution, and requests termination on exceptions
    public:
        using _Standard_execution_policy   = int;
        static constexpr bool _Parallelize = false;
        static constexpr bool _Ivdep       = false;
    };

    inline constexpr sequenced_policy seq{/* unspecified */};

    class parallel_policy {
        // indicates support by element access functions for parallel execution with parallel forward progress
        // guarantees, and requests termination on exceptions
    public:
        using _Standard_execution_policy   = int;
        static constexpr bool _Parallelize = true;
        static constexpr bool _Ivdep       = true;
    };

    inline constexpr parallel_policy par{/* unspecified */};

    class parallel_unsequenced_policy {
        // indicates support by element access functions for parallel execution with weakly parallel forward progress
        // guarantees, and requests termination on exceptions
        //
        // (at this time, equivalent to parallel_policy)
    public:
        using _Standard_execution_policy   = int;
        static constexpr bool _Parallelize = true;
        static constexpr bool _Ivdep       = true;
    };

    inline constexpr parallel_unsequenced_policy par_unseq{/* unspecified */};

#if _HAS_CXX20
    class unsequenced_policy {
        // indicates support by element access functions for weakly parallel forward progress guarantees, and for
        // executing interleaved on the same thread, and requests termination on exceptions
        //
        // (at this time, equivalent to sequenced_policy except for the for_each family)
    public:
        using _Standard_execution_policy   = int;
        static constexpr bool _Parallelize = false;
        static constexpr bool _Ivdep       = true;
    };

    inline constexpr unsequenced_policy unseq{/* unspecified */};
#endif // _HAS_CXX20

} // namespace execution

std::sequenced_policy seq

  1. 执行策略类型,用作对并行算法重载消歧义的独有类型,并要求并行算法的执行可以不并行化。以此策略调用(通常以 std::execution::seq 指定)的并行算法中,元素访问函数的调用在调用方线程中是非确定顺序的。
/**
 * 串行策略
 * indicates support for only sequential execution
 * 指示仅支持顺序执行
 * and requests termination on exceptions
 * 并在异常时终止请求
 */
class sequenced_policy {
    // indicates support for only sequential execution, and requests termination on exceptions
public:
    using _Standard_execution_policy   = int;
    static constexpr bool _Parallelize = false;
    static constexpr bool _Ivdep       = false;
};

inline constexpr sequenced_policy seq{/* unspecified */};

std::parallel_policy par

  1. 执行策略类型,用作对并行算法重载消歧义的独有类型,并指示并行算法的执行可以并行化。以此策略调用(通常以 std::execution::par 指定)的并行算法中,元素访问函数的调用允许在调用方线程,或由库隐式创建的用以支持并行算法执行的线程中执行。任何执行于同一线程中的这种调用彼此间是非确定顺序的,
/**
 * 并行执行策略
 * indicates support by element access functions for parallel execution with parallel forward
 * progress guarantees
 * 指示元素访问函数支持并行执行,并保证并行向前进度
 * and requests termination on exceptions
 * 并在异常时终止请求
 */
class parallel_policy {
    // indicates support by element access functions for parallel execution with parallel forward
    // progress guarantees, and requests termination on exceptions
public:
    using _Standard_execution_policy   = int;
    static constexpr bool _Parallelize = true;
    static constexpr bool _Ivdep       = true;
};

inline constexpr parallel_policy par{/* unspecified */};

std::parallel_unsequenced_policy par_unseq

  1. 执行策略类型,用作对并行算法重载消歧义的独有类型,并指示并行算法的执行可以并行化、向量化,或在线程间迁移(例如用亲代窃取式调度器)。以此策略调用的并行算法中,容许在未指定线程中以无序方式来执行元素访问函数调用,并相对于各个线程中的另一调用间无顺序。
/**
 * 并行无序执行策略
 * indicates support by element access functions for parallel execution with weakly parallel
 * forward progress guarantees
 * 指示元素访问函数支持并行执行,并提供弱并行向前进度保证
 * and requests termination on exceptions
 * 并在异常时终止请求
 * (at this time, equivalent to parallel_policy)
 * (此时,相当于并行策略)
 */
class parallel_unsequenced_policy {
    // indicates support by element access functions for parallel execution with weakly parallel
    // forward progress guarantees, and requests termination on exceptions
    //
    // (at this time, equivalent to parallel_policy)
public:
    using _Standard_execution_policy   = int;
    static constexpr bool _Parallelize = true;
    static constexpr bool _Ivdep       = true;
};

inline constexpr parallel_unsequenced_policy par_unseq{/* unspecified */};

std::unsequenced_policy unseq

  1. 执行策略类型,用作对并行算法重载消歧义的独有类型,并指示可将算法的执行向量化,例如在单个线程上使用操作多个数据项的指令执行。
#if _HAS_CXX20
/**
 * 无序执行策略
 * indicates support by element access functions for weakly parallel forward progress guarantees
 * 指示元素访问函数支持弱并行向前进度保证
 * and for executing interleaved on the same thread
 * 支持在同一线程上交错执行
 * and requests termination on exceptions
 * 以及在异常时终止请求
 * (at this time, equivalent to sequenced_policy except for the for_each family)
 * (此时,相当于sequenced_policy,除了for_each一类)
 */
class unsequenced_policy {
    // indicates support by element access functions for weakly parallel forward progress
    // guarantees, and for executing interleaved on the same thread, and requests termination on
    // exceptions
    //
    // (at this time, equivalent to sequenced_policy except for the for_each family)
public:
    using _Standard_execution_policy   = int;
    static constexpr bool _Parallelize = false;
    static constexpr bool _Ivdep       = true;
};

inline constexpr unsequenced_policy unseq{/* unspecified */};
#endif  // _HAS_CXX20

END

关注我,学习更多C/C++,算法,计算机知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值