您的位置:首页 > 新闻 > 会展 > 沈阳建设工程信息网 放心中项网_b2b电子平台有哪些_搜狗网站收录_公众号推广平台

沈阳建设工程信息网 放心中项网_b2b电子平台有哪些_搜狗网站收录_公众号推广平台

2025/1/8 7:02:36 来源:https://blog.csdn.net/arong_xu/article/details/144991044  浏览:    关键词:沈阳建设工程信息网 放心中项网_b2b电子平台有哪些_搜狗网站收录_公众号推广平台
沈阳建设工程信息网 放心中项网_b2b电子平台有哪些_搜狗网站收录_公众号推广平台

在现代 C++ 中, 提升程序性能的需求日益增长, 而并行计算和矢量化逐渐成为高性能计算的核心手段. 为了帮助开发者简化并行化操作, C++17 引入了 std::execution 命名空间, 为标准算法提供了一种简单且强大的执行策略机制. 这篇博客将深入介绍 std::execution 的概念, 使用方法及其优势.


什么是 std::execution?

std::execution 是 C++ 标准库中的一个命名空间, 定义了几种 执行策略(Execution Policies), 用于控制标准算法的执行模式. 这些执行策略可以显式指定算法是以串行, 并行还是矢量化的方式执行.

通过使用 std::execution, 开发者可以更高效地利用多核 CPU 和 SIMD 指令集, 从而在性能上实现显著提升, 而无需手动管理多线程或矢量化的复杂逻辑.


执行策略概览

std::execution 提供了以下四种执行策略:

  1. std::execution::seq(串行执行):

    • 算法按默认的顺序依次执行.
    • 无并行化, 也不进行矢量化.
  2. std::execution::par(并行执行):

    • 算法以多线程的方式并行执行.
    • 适合多核处理器的计算密集型任务.
  3. std::execution::par_unseq(并行且矢量化执行):

    • 算法在并行的基础上进一步允许矢量化.
    • 利用硬件能力实现更高效的计算.
  4. std::execution::unseq(矢量化执行):

    • 算法允许矢量化, 但不保证迭代顺序.
    • 利用 SIMD 指令提升单线程性能.

std::execution 的使用方法

std::execution 的核心用途是与 C++ 标准算法相结合, 通过简单地传递执行策略作为参数, 指定算法的执行模式.

示例 1: 并行排序

#include <algorithm>
#include <chrono>
#include <execution>
#include <iostream>
#include <random>
#include <vector>int main() {// 生成随机数据集constexpr size_t kTotalCount = 1'000'000;std::vector<int> data(kTotalCount);std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<> dis(1, kTotalCount);for (auto& d : data) {d = dis(gen);}// 串行排序并计时auto start_seq = std::chrono::high_resolution_clock::now();std::sort(data.begin(), data.end());auto end_seq = std::chrono::high_resolution_clock::now();std::cout << "串行排序耗时: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end_seq -start_seq).count()<< " ms" << std::endl;// 打乱数据顺序std::shuffle(data.begin(), data.end(), gen);// 并行排序并计时auto start_par = std::chrono::high_resolution_clock::now();std::sort(std::execution::par, data.begin(), data.end());auto end_par = std::chrono::high_resolution_clock::now();std::cout << "并行排序耗时: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end_par -start_par).count()<< " ms" << std::endl;std::shuffle(data.begin(), data.end(), gen);// 矢量化排序并计时auto start_unseq = std::chrono::high_resolution_clock::now();std::sort(std::execution::unseq, data.begin(), data.end());auto end_unseq = std::chrono::high_resolution_clock::now();std::cout << "矢量化排序耗时: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end_unseq - start_unseq).count()<< " ms" << std::endl;std::shuffle(data.begin(), data.end(), gen);// 并行且矢量化排序并计时auto start_par_unseq = std::chrono::high_resolution_clock::now();std::sort(std::execution::par_unseq, data.begin(), data.end());auto end_par_unseq = std::chrono::high_resolution_clock::now();std::cout << "并行且矢量化排序耗时: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end_par_unseq - start_par_unseq).count()<< " ms" << std::endl;return 0;
}

在这个示例中, std::execution::par 指定 std::sort 可以利用多线程并行化排序操作.
笔者测试了不同的编译器, 结果如下:

  1. GCC, 未开-O3优化
    串行排序耗时: 348 ms
    并行排序耗时: 381 ms
    矢量化排序耗时: 381 ms
    并行且矢量化排序耗时: 370 ms
    
  2. Clang 18.1.3, 未开-O3优化
    串行排序耗时: 355 ms
    并行排序耗时: 406 ms
    矢量化排序耗时: 419 ms
    并行且矢量化排序耗时: 384 ms
    
  3. MSVC
    串行排序耗时: 309 ms
    并行排序耗时: 81 ms
    矢量化排序耗时: 321 ms
    并行且矢量化排序耗时: 57 ms
    

可以看到 GCC/Clang 对此方面的优化不是很好, 而 MSVC 则对并行排序优化的比较好.

示例 2: 并行处理数据

#include <execution>
#include <vector>
#include <numeric>
#include <iostream>
#include <chrono>int main() {std::vector<int> data(1'000'000, 1);// 串行归约操作并计时auto start_seq = std::chrono::high_resolution_clock::now();int sum_seq = std::accumulate(data.begin(), data.end(), 0);auto end_seq = std::chrono::high_resolution_clock::now();std::cout << "串行归约耗时: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end_seq - start_seq).count()<< " ms" << std::endl;// 并行归约操作并计时auto start_par = std::chrono::high_resolution_clock::now();int sum_par = std::reduce(std::execution::par, data.begin(), data.end(), 0);auto end_par = std::chrono::high_resolution_clock::now();std::cout << "并行归约耗时: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end_par - start_par).count()<< " ms" << std::endl;// 输出结果std::cout << "串行归约结果: " << sum_seq << std::endl;std::cout << "并行归约结果: " << sum_par << std::endl;return 0;
}

在上述代码中, std::reduce 使用 std::execution::par 实现了并行化的数据归约(reduce)操作.

输出结果:

  1. GCC 14.2
    串行归约耗时: 14 ms
    并行归约耗时: 9 ms
    
  2. Clang 18.1.3
    串行归约耗时: 16 ms
    并行归约耗时: 12 ms
    
  3. MSVC
    串行归约耗时: 8 ms
    并行归约耗时: 4 ms
    

std::execution 支持的算法

在 C++17 中, 标准库中的许多算法都支持执行策略, 包括但不限于:

  • std::for_each: 遍历并处理元素.
  • std::transform: 对每个元素应用变换操作.
  • std::reduce: 并行归约操作.
  • std::sort: 并行排序.

使用建议与注意事项

  1. 线程安全性:

    • 并行执行策略(parpar_unseq)要求代码中的所有数据操作是线程安全的, 尤其是写入共享资源时需要加锁.
  2. 适用场景:

    • 对于小规模数据集, 串行执行(seq)可能性能更好, 因为并行化带来的开销可能超过其带来的收益.
    • 对于数据独立的计算任务, 并行策略(parpar_unseq)能显著提升性能.
  3. 硬件依赖:

    • 并行化性能提升取决于硬件是否支持多核处理和 SIMD 指令.
  4. 非确定性行为:

    • 并行策略(parpar_unseq)不保证执行顺序, 因此对顺序敏感的任务不适合使用这些策略.

性能提升的核心原因

  • 并行化: 任务被划分为多个线程执行, 充分利用多核 CPU 的资源.
  • 矢量化: 通过 SIMD 指令同时处理多个数据元素, 提升计算密度.
  • 任务分解: 标准库会自动将任务分解为多个子任务, 最大化硬件利用率.

总结

std::execution 是 C++17 提供的一个强大工具, 它为标准算法赋予了更灵活的执行模式, 简化了并行计算的实现方式. 通过指定执行策略, 开发者可以更高效地利用硬件资源, 从而显著提升程序性能.

无论是大规模数据处理还是高性能计算场景, std::execution 都是不可或缺的利器. 熟练掌握它, 将为你的 C++ 编程技能增添一份强大的武器.

源码链接

源码链接

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com