当前位置: 首页 > news >正文

C++17并行化加速STL算法——std::execution

C++17 并行化STL算法

文章目录

  • C++17 并行化STL算法
    • 概念
      • 环境准备
      • 工具类
    • 并行算法 - 使用
    • 并行算法 - 执行策略
      • 总览
      • 选择标准
      • 详细介绍
        • 顺序执行 seq
        • 并行化顺序执行 par
        • 并行化乱序执行 par_unseq
    • 并行算法 - 异常处理
    • 可以不使用并行算法
    • 并行算法 - 限制
    • 并行算法有哪些
      • 原有算法
      • 17引入新算法

概念

为了从现代的多核体系中受益,C++17标准库引入了并行 STL算法,允许使用多个线程并行处理元素。

C++17为许多算法扩展了一个新的参数来指明是否要并行运行算法。并且新增了一些专为并行编程补充的新算法。

环境准备

并行算法在 linux上使用 gcc 或者 clang进行编译,需要

  1. 安装 tbb库—— 线程构建模块 (TBB) Thread Building Blocks
  2. 链接时指定-ltbb选项

否则:

tbb链接结果
安装指定-ltbb选项可正常使用并行算法
安装未指定编译错误
未安装指定编译错误
未安装未指定正常编译,但并行算法会串行化,变得和串行算法一样
# 编译选项
g++ ‐std=c++17 ‐ltbb main.cpp ‐o a.out

工具类

有时需要计时器来测量算法的速度。因此,引入一个简单的辅助类。

初始化一个计时器,提供 printDiff()来打印出消耗的毫秒数 并 重新初始化计时器

#include <iostream>
#include <string>
#include <chrono>
/********************************************
* timer to print elapsed time
********************************************/
class Timer {
private:std::chrono::steady_clock::time_point last;
public:Timer() : last{std::chrono::steady_clock::now()} {}void printDiff(const std::string& msg = "Timer diff: ") {auto now{std::chrono::steady_clock::now()};std::chrono::duration<double, std::milli> diff{now ‐ last};std::cout << msg << diff.count() << "ms\n";last = std::chrono::steady_clock::now();}
};

并行算法 - 使用

怎么让现有算法并行运行和使用新的并行算法

  • 包含头文件 <execution>
#include <execution> 
  • C++17之后,一般来说可以向并行 STL算法传递不同的 执行策略 (execution policies) 作为第一个参数。

    • cpprefrence上看看STL算法支不支持,一般是:添加执行策略到第一个参数即可。例如,std::execution::par

    • 使用参数 传递/修改 执行策略 的好处:可在运行时更改策略时(顺序执行/并行执行),不需要再修改调用方式。

所有的并行算法要求迭代器至少是前向迭代器。

#include <execution> // for 执行策略
#include <algorithm>std::vector<std::string> coll {"a", "b", "c"};sort(coll.begin(), coll.end());
sort(std::execution::seq, coll.begin(), coll.end());
sort(std::execution::par, coll.begin(), coll.end());
sort(std::execution::par_unseq, coll.begin(), coll.end());// 并行计算平方根
for_each(std::execution::par,coll.begin(), coll.end(),[] (auto& val) {val.sqrt = std::sqrt(val.value);});

并行算法 - 执行策略

总览

以下执行策略,分别是定义在 namespace std中的新类(sequenced_policyparallel_policyparallel_unsequenced_policy)的 constexpr对象。

执行策略含义
std::execution::seq顺序执行
std::execution::par并行化顺序执行
std::execution::par_unseq并行化乱序(矢量化)执行

标准库提供了新的类型特征 std::is_execution_policy<>,在泛型编程中检查模板参数是否是执行策略。

并行化乱序执行需要编译器/硬件的特殊支持,从而检测如何矢量化。

非并行化/并行化

  1. 并行化——多个线程执行
  2. 非并行化——单一线程

顺序、乱序

  1. 乱序:允许矢量化执行,不保证顺序地对元素执行操作。

    即存在可能:

    • 某个线程在执行完某一个元素的处理之前可能会切换到其他的元素。

    • 某个线程先执行多个元素的第一步处理,再回过头来对这些元素执行下一步处理。

  2. 顺序:不允许矢量化执行,顺序地对元素执行操作

    当某个线程对新的元素进行操作之前,它会先处理完它之前处理过的其他元素。

选择标准

benchmark测试结果,主要依赖于硬件、使用的 C++编译器、使用的 C++库(并行算法实际运行的方式是实现特定的)

没有通用的方法来判断什么场景什么时间值得使用并行算法。不能说多线程就一定比顺序执行好:启动和控制多线程也会消耗时间

理论上讲,如下判断依据可以作为参考:

  • 简单算法(每个元素计算耗时短),元素数量少。并行执行永远会更慢建议顺序执行 std::execution::seq 或 默认版本。

  • 复杂算法(每个元素计算耗时长),元素数量多。适合使用并行算法

    • 处理过程需要独立于其他元素的处理 —— 并行化顺序执行 std::execution::par
    • 处理过程不需要独立于其他元素的处理 —— 并行化乱序执行 std::execution::par_unseq

详细介绍

顺序执行 seq

std::execution::seq 指定顺序执行

  • 策略本身:

    • 单一线程执行
    • 单个线程对所有元素逐个执行操作。不允许矢量化执行,顺序地对元素执行操作——当某个线程对新的元素进行操作之前,它会先处理完它之前处理过的其他元素。
  • 与非并行化版本进行对比

    • 实际上,该策略非常类似不接受执行策略参数的非并行化版本
    • 但多一些约束条件:例如 for_each()不能返回值,所有的迭代器必须至少是前向迭代器
  • 提供该策略的目的:

    • 可只修改一个参数来要求顺序执行,而不是换用一个签名不同的函数。
并行化顺序执行 par

std::execution::par 指定并行化顺序执行

  • 策略本身:

    • 多个线程执行
    • 顺序执行:允许矢量化
  • 提供该策略的目的:

    • 比非并行化顺序执行,可能要快一些

    • 避免在以下情况中出现死锁或其它bug(与 par_unseq不同)

      执行了某个元素的第一步处理后必须在执行另一个元素的第一步处理之前执行这个元素接下来的处理步骤。

并行化乱序执行 par_unseq

std::execution::par_unseq 指定并行化乱序执行

  • 策略本身:
    • 多个线程执行
    • 乱序执行:允许矢量化
  • 提供该策略的目的:
    • 比非矢量化 顺序执行,可能要快一些

并行化乱序执行需要编译器/硬件的特殊支持来检测哪些操作如何矢量化。

并行算法 - 异常处理

当指定了执行策略后:

  • 处理元素的函数,因未捕获的异常而退出时,会调用 std::terminate()

  • 注意即使选择了顺序执行策略也会这样。

注意:存在并行算法本身抛出异常的可能性!

例如,申请并行执行所需的临时内存资源时失败了,会抛出 std::bad_alloc 异常。从而直接 std::terminate()

所以,使用非并行化版本的算法有时是更好的选择。

可以不使用并行算法

使用非并行算法可以提供以下好处:

  • 可以使用输入和输出迭代器。
  • 算法不会在遇到异常时 std::terminate()
  • 算法可以避免因为意外使用元素导致的副作用。
  • 算法可以提供额外的功能,例如 for_each()会返回传入的可调用对象,我们可能会需要该对象最终的状态

并行算法 - 限制

有限制的并行 STL算法

限制:返回类型 void、前向迭代器

for_each()

限制:前向迭代器

for_each_n() all_of(), and_of(), none_of() 
find(), find_if(), find_if_not() 
find_first_of() 
count(), count_if() 
mismatch() 
equal() 
is_partitioned() 
partial_sort_copy() 
includes() 
lexicographical_compare() 
fill_n() 
generate_n() 
reverse_copy() 
rotate_copy() 
copy(), copy_n(), copy_if() 
move() 
transform() 
replace_copy(), replace_copy_if() 
remove_copy(), remove_copy_if() 
unique_copy() 
partition_copy() 
merge() 
set_union(), set_intersection() 
set_differrnce(), set_symmetric_difference() 
inclusive_scan(), exclusive_scan() 
transform_inclusive_scan(), transform_exclusive_scan()

并行算法有哪些

原有算法

C++17之前,标准中不需要修改就可以并行运行的算法

find_end(), adjacent_find()
search(), search_n()(和“搜索器”一起使用时除外)
swap_ranges()
replace(), replace_if()
fill()
generate()
remove(), remove_if(), unique()
reverse(), rotate()
partition(), stable_partition()
sort(), stable_sort(), partial_sort()
is_sorted(), is_sorted_until()
nth_element()
inplace_merge()
is_heap(), is_heap_until()
min_element(), max_element(), min_max_element()

无并行版本的算法

  • 为了并行地运行 accumulate(),使用reduce() 或者transform_reduce()。
  • 为了并行地运行 partial_sum(),使用…scan()算法。
  • 为了并行地运行 inner_product(),使用transform_reduce()。
accumulate()
partial_sum()
inner_product()
search()(和“搜索器”一起使用时)
copy_backward(), move_backward()
sample(), shuffle()
partition_point()
lower_bound(), upper_bound(), equal_range()
binary_search()
is_permutation()
next_permutation(), prev_permutation()
push_heap(), pop_heap(), make_heap(), sort_heap()

17引入新算法

相关文章:

C++17并行化加速STL算法——std::execution

C17 并行化STL算法 文章目录 C17 并行化STL算法概念环境准备工具类 并行算法 - 使用并行算法 - 执行策略总览选择标准详细介绍顺序执行 seq并行化顺序执行 par并行化乱序执行 par_unseq 并行算法 - 异常处理可以不使用并行算法并行算法 - 限制并行算法有哪些原有算法17引入新算…...

从sumsub获取用户图片

已经拿到了imageid 然后从哪个接口可以获取图片文件呢&#xff1f; 根据您的问题,我可以为您提供以下信息: 一旦您获得了imageId,您可以使用以下几个API接口来获取图片文件: 获取文档图片: Get document images GET https://api.sumsub.com/resources/inspections/{inspection…...

DeepSeek + Mermaid编辑器——常规绘图

下面这张图出自&#xff1a;由清华大学出品的 《DeepSeek&#xff1a;从入门到精通》。 作为纯文本生成模型&#xff0c;DeepSeek虽不具备多媒体内容生成接口&#xff0c;但其开放式架构允许通过API接口与图像合成引擎、数据可视化工具等第三方系统进行协同工作&#xff0c;最终…...

ARM64 Trust Firmware [五 ]

本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。 要了解 SMC&#xff0c;必须从 SMC 指令本身开始&#xff0c;其指令如下图&#xff1a; 指令格式为&#xff1a;SMC #<imm>&#xff0c;从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用&#xff…...

Excel核心函数VLOOKUP全解析:从入门到精通

一、函数概述 VLOOKUP是Excel中最重要且使用频率最高的查找函数之一&#xff0c;全称为Vertical Lookup&#xff08;垂直查找&#xff09;。该函数主要用于在数据表的首列查找特定值&#xff0c;并返回该行中指定列的对应值。根据微软官方统计&#xff0c;超过80%的Excel用户在…...

KTransformers如何通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度?

KTransformers通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度&#xff0c;具体体现在以下几个方面&#xff1a; 内核级优化&#xff1a; KTransformers采用了高效的内核级优化技术&#xff0c;包括对Transformer模型中的关键操作进行优化。例如…...

审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空

如果查询 DBA_AUDIT_TRAIL 时发现 SQL_TEXT 列为空&#xff0c;但其他字段&#xff08;如 OS_USERNAME、USERNAME、TIMESTAMP 等&#xff09;有数据&#xff0c;可能是由于以下原因之一。以下是可能的原因及解决方法&#xff1a; 1. 审计级别未启用扩展模式 默认情况下&#x…...

微信小程序项目 video 组件失效问题,无法播放本地视频

问题与处理策略 问题描述 <video src"../../assets/video/test-video.mp4" controls style"width: 100%; height: 300px;"></video>在微信小程序项目中&#xff0c;上述 video 组件失效&#xff0c;视频无法加载&#xff0c;无法播放本地视频…...

若依-@Excel新增注解numberFormat

Excel注解中原本的scale会四舍五入小数&#xff0c;导致进度丢失 想要的效果 显示的时候保留两个小数真正的数值是保留之前的数值 还原过程 若以中有一個專門的工具类&#xff0c;用来处理excel的 找到EXCEL导出方法exportExcel()找到writeSheet,写表格的方法找到填充数据的方法…...

网络安全行业有哪些公司

只是简单做一下网络安全公司梳理&#xff0c;不作点评&#xff0c;下列排名不分先后。 一、常见的网络安全公司 1、天融信 天融信&#xff08;002212.SZ&#xff09;创始于1995年&#xff0c;是上市公司中成立最早的网络安全企业&#xff0c;亲历中国网络安全产业的发展历程…...

存储区域网络(SAN)管理

存储区域网络&#xff08;Storage Area Network&#xff0c;SAN&#xff09;采用网状通道&#xff08;Fibre Channel &#xff0c;简称FC&#xff09;技术&#xff0c;通过FC交换机连接存储阵列和服务器主机&#xff0c;建立专用于数据存储的区域网络。SAN提供了一种与现有LAN连…...

如何使用Spark SQL进行复杂的数据查询和分析

使用Spark SQL进行复杂的数据查询和分析是一个涉及多个步骤和技术的过程。以下是如何使用Spark SQL进行复杂数据查询和分析的详细指南&#xff1a; 一、准备阶段 环境搭建&#xff1a; 确保已经安装并配置好了Apache Spark环境。准备好数据源&#xff0c;可以是CSV文件、JSON…...

sass报错:[sass] Undefined variable. @import升级@use语法注意事项

今天创建vue3项目&#xff0c;迁移老项目代码&#xff0c;使用sass的时候发现import语法已经废弃&#xff0c;官方推荐使用use替换。 这里我踩了一个坑找半天的问题&#xff0c;原因是sass升级到1.85之后 定义变量前加上 - 就是表示变量私有&#xff0c;即使使用use导出 在新的…...

使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)安装适配 Java 8 的 Maven

文章目录 1、安装 SDKMAN!2、安装 Maven:2.1、maven 3.9.62.2、maven 3.8.1 好的&#xff0c;这是使用 SDKMAN! 安装适配 Java 8 的 Maven 的步骤&#xff1a; 1、安装 SDKMAN! 前提条件: 安装 SDKMAN!: 如果你的系统上没有安装 SDKMAN!&#xff0c;请按照以下说明进行安装: c…...

anythingllm服务器部署+ollama+deepseek+实现本地知识库问答

一、docker安装anythingllm 1、拉取镜像 docker pull mintplexlabs/anythingllm:latest 2、创建db目录和配置文件并运行 anythingLLM 容器 export STORAGE_LOCATION/data/ai/wjh_team/anythingllm && \mkdir -p $STORAGE_LOCATION && \touch "$STORAG…...

深度学习04 数据增强、调整学习率

目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 ​调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 ​自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换&#xff08;如旋转、翻转、裁剪等&#xff09;&am…...

2023年全国职业院校技能大赛GZ073网络系统管理赛项赛题第10套模块A:网络构建

​有问题请留言或主页私信咨询 2023年全国职业院校技能大赛 GZ073网络系统管理赛项 赛题第10套 模块A&#xff1a;网络构建 ​ ​ **目 **录 任务清单 &#xff08;一&#xff09;基础配置 &#xff08;二&#xff09;有线网络配置 &#xff08;三&#xff09;无线…...

2023年河北省职业院校技能大赛网络系统管理赛项样题解法

​ 有问题请留言或主页私信咨询 配置文件有部分测试时的冗余配置无视即可。 解法只有大致解法&#xff0c;并不完整。请参考配置&#xff0c;自己补全 基础配置 1.所有交换机和无线控制器开启SSH服务&#xff0c;用户名密码分别为admin、admin1234&#xff1b;密码为明文类…...

vite+vue3开发uni-app时低版本浏览器不支持es6语法的问题排坑笔记

重要提示&#xff1a;请首先完整阅读完文章内容后再操作&#xff0c;以免不必要的时间浪费&#xff01;切记&#xff01;&#xff01;&#xff01;在使用vitevue3开发uni-app项目时&#xff0c;存在低版本浏览器不兼容es6语法的问题&#xff0c;如“?.” “??” 等。为了方便…...

Linux系统编程基础详解

Linux 系统详解 大纲 引言 Linux 的定义Linux 的历史与发展本文结构概述 Linux 的基本概念 Linux 的架构 内核与用户空间系统调用 Linux 的文件系统 文件与目录结构权限管理 Linux 的进程管理 进程与线程进程调度 Linux 的基本命令与操作 常用命令概述 文件与目录操作命令文…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...