Modern Effective C++条款三十五:优先考虑基于任务的编程而非基于线程的编程
C++中开发者可以通过两种主要方式异步执行一个函数,如doAsyncWork()。这两种方法分别是基于线程(thread-based)和基于任务(task-based)的方式。
基于线程的方式
使用std::thread创建一个新的线程来执行doAsyncWork()函数,直接且直观,但也有其局限性。
int doAsyncWork();
std::thread t(doAsyncWork);
(1)资源管理:开发者需要负责线程的生命周期管理,确保线程正确地启动、运行和结束。
(2)返回值处理:如果doAsyncWork有返回值或需要处理结果,基于线程的方法并不直接支持这一点。必须通过额外的机制(例如共享变量、管道等)来传递结果,增加复杂性。
(3)异常处理:如果doAsyncWork抛出异常,线程会调用std::terminate终止整个程序,除非在线程内部捕获了异常。
基于任务的方式
使用std::async将doAsyncWork作为任务提交,自动处理任务的调度和执行,并返回一个std::future对象用于获取任务的结果。
auto fut = std::async(doAsyncWork); // "fut"表示"future"
(1)简化代码:相比基于线程的方法,std::async的语法更简洁,减少了代码量。
(2)方便获取返回值:std::future提供了get方法,可以直接获取异步操作的结果或处理异常,而无需额外的同步机制。
(3)内置异常处理:如果任务抛出了未捕获的异常,get方法调用时会重新抛出该异常,允许调用者以受控方式处理异常,而不是直接导致程序崩溃。
选择哪种方式?
基于任务的方法通常优于基于线程的方法,尤其是在需要处理返回值或可能发生的异常的情况下。std::async简化了异步编程模型,提高代码的可读性和维护性。然而对于一些特定的应用场景,比如需要对线程进行细粒度控制时,基于线程的方法可能仍然是必要的。
在C++并发编程,基于线程和基于任务的方式有本质的区别。"Thread”的三种含义
(1)硬件线程(Hardware Threads)
物理CPU核心上实际执行计算的能力。现代计算机架构通常为每个CPU核心提供一个或多个硬件线程,以支持并行处理。
(2)软件线程(software threads)或系统线程(OS Threads)
由操作系统管理,在硬件线程上运行的任务单元。操作系统可以调度更多的软件线程,超过硬件线程的数量,以便当某些线程被阻塞时(例如等待I/O操作完成),其他线程可以继续执行,从而提高整体吞吐量。
(3)std::thread对象
这是C++标准库提供的类,作为软件线程的句柄。它可以代表一个正在运行的软件线程,也可以是未关联任何线程的空句柄(如默认构造的std::thread)。通过std::thread,我们可以启动、暂停、等待线程结束或分离线程。
线程资源的限制
(1)线程限额:操作系统能够支持的线程数量是有限的。如果尝试创建超出这个限额的线程,会抛出std::system_error异常。即使函数本身声明为noexcept,也不能避免这种情况发生。
(2)资源超额:当准备运行的软件线程数超过了可用硬件线程的数量时,就会出现资源超额的情况。这会导致操作系统频繁地进行上下文切换,增加调度开销,降低效率。此外,由于不同的软件线程可能在不同的硬件线程间迁移,导致缓存不友好,影响性能。
设计良好并发软件需要考虑以下策略:
线程池(Thread Pool):使用线程池来重用一组固定的线程,而不是为每个任务创建新的线程。这有助于控制线程数量,减少上下文切换和初始化开销。
任务调度(Task Scheduling):采用更高级别的任务调度机制,比如使用std::async或第三方库,它们可以根据当前系统的负载动态调整任务的分配,确保高效的资源利用。
异步I/O和非阻塞操作:尽量使用异步I/O和非阻塞API,减少线程因等待外部资源而阻塞的可能性,从而提高并发性。
使用std::async的优势
std::async提供了一种更高级别的抽象,将线程管理的责任交给了标准库的开发者。
(1)简化线程管理:开发者不再需要直接处理线程创建、销毁等细节问题。
(2)减少资源超额的风险:std::async默认启动策略并不保证会立即创建新的线程,而是允许调度器根据系统资源情况灵活决定任务的执行方式。例如,在资源紧张时,它可以选择在等待结果的线程上执行任务,而不是开启新线程。
(3)提高负载均衡:运行时调度程序对整个系统的执行过程有更全面的理解,能够更好地处理负载不均衡的问题。
(4)利用先进的调度技术:最前沿的线程调度器采用系统级线程池和工作窃取算法来优化资源利用和跨核心负载均衡。
适用场景与局限性
访问底层线程API:当需要使用非常基础的线程功能或操作系统级别的特性(如线程优先级、亲和性等),std::thread提供的native_handle成员函数可以直接访问底层API,而std::future不具备这种能力。
优化线程使用:对于已知执行概况的应用程序(如服务器软件),如果部署环境固定且作为唯一关键进程,可能更适合直接管理线程以实现最优性能。
实现特殊线程技术:当需要使用C++并发API之外的技术(如未被支持的平台上的线程池)时,std::thread提供了更大的灵活性。
工作窃取算法
任务分割:一个大的任务被分割成若干个互不依赖的小任务,这些小任务可以独立地并行执行。
队列分配:每个工作线程拥有自己的双端队列(deque),用来存储待处理的任务。线程通常会从自己队列的头部(front)获取任务执行。
任务窃取:当某个线程完成了自己队列中的所有任务而变得空闲时,它可以尝试从其他线程队列的尾部(back)窃取任务来执行。这样可以避免直接竞争同一个队列的头部位置,从而降低锁争用的可能性。
双端队列的作用:使用双端队列的原因是为了让原线程可以从一端高效地添加和移除任务(通常是从前端),同时允许其他线程从另一端安全地窃取任务而不引起冲突。
std::thread
API不能直接访问异步执行的结果,如果执行函数有异常抛出,代码会终止执行。- 基于线程的编程方式需要手动的线程耗尽、资源超额、负责均衡、平台适配性管理。
- 通过带有默认启动策略的
std::async
进行基于任务的编程方式会解决大部分问题。
相关文章:
Modern Effective C++条款三十五:优先考虑基于任务的编程而非基于线程的编程
C中开发者可以通过两种主要方式异步执行一个函数,如doAsyncWork()。这两种方法分别是基于线程(thread-based)和基于任务(task-based)的方式。 基于线程的方式 使用std::thread创建一个新的线程来执行doAsyncWork()函数,直接且直观,但也有其…...
lyapunov指数的绘制
有如下方程: %% 方程式 % x(n1)1y(n)-a*x(n)^2 % y(n1)b*x(n)绘制其对应的lyapunov指数。 MATLAB实现方式: clc; clearvars; close all;%% 方程式 % x(n1)1y(n)-a*x(n)^2 % y(n1)b*x(n)%% 代码 N 1000; a (0:0.001:1.4); b 0.3; na length(a…...
WPF+MVVM案例实战与特效(三十二)- 封装一个Appconfig 操作类(保留注释)
文章目录 1、概述2、ConfigHelper 的功能3、代码实现1、ConfigHelper.cs 代码2、帮助类使用4、总结1、概述 在开发 WPF 应用程序时,配置文件(如 App.config )是存储应用程序设置、连接字符串和其他运行时信息的常用方式。然而,直接操作这些配置文件可能会涉及到复杂的 XML…...
决策树:ID3、C4.5和CART特征选择方式
1 前言 该文章主要目的是记录ID3、C4.5和CART特征选择方式,这里只对决策树进行简单介绍。 决策树(Decision Tree)算法是一种有监督学习算法,它利用分类的思想,根据数据的特征构建数学模型,从而达到数据的筛…...
02 conda常用指令
目录 命令快速查找命令详细解释列出当前conda中存在的解释器环境使用指定的解释器环境创建虚拟环境激活自己创建的虚拟环境虚拟环境删除切换回主环境找到你计算机中安装的miniconda3的跟目录找到虚拟环境的目录选择需要删除的虚拟环境文件夹确认环境是否删除 补充删除虚拟环境指…...
从仪表盘探索 MongoDB 关键指标
这是 MongoDB 监控系列文章的第七篇,前面几篇文章的链接如下: MongoDB 监控(一)MongoDB 监控(二)MongoDB 监控(三)MongoDB 监控(四)MongoDB 监控(…...
Grule前端表单post后端执行grule引擎规则
Grule前端表单post后端执行grule引擎规则 编写前端表单和后端接口 编写test.go执行grule引擎规则 示例都是 go test 执行的测试代码,所以将里面的测试代码去除 由于之前 NumberExponentExample_test.go 已经验证可运行, 所以将 err 的异常处理去除 package mai…...
EasyRTC支持嵌入式智能硬件与微信小程序实时通话
基础建设如此发达的时代,各种物联网设备都越来越普及,尤其是可穿戴设备和智能家居设备的发展,而在物联网设备中,视频物联网设备又是特别受人关注的设备,因为他们具备有看得见的属性,像智能家居里面的摄像头…...
openGauss开源数据库实战十九
文章目录 任务十九 openGauss DML 语句测试任务目标实施步骤一、准备工作二、INSERT语句三、DELETE语句四、UPDATE语句五、清理工作 任务十九 openGauss DML 语句测试 任务目标 掌握DML语句的用法,包括INSERT语句、DELETE语句和UPDATE语句。 实施步骤 一、准备工作 使用Li…...
基于XML的AOP开发
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程。 AOP相关术语: 目标对象(Target): 你要去代理的对象,可以理解为之前很单纯的那个对象。 代理对象(Proxy): 你把你那个单纯的对象给我,…...
获取Ubuntu-22.04.1 对应的vmlinux文件
0.前言 🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言…...
Python后端 -- 万字长文全面解析Django框架
自从2005年诞生以来,Django因其“开发速度快、安全性高”的特点迅速成为许多开发者的首选。无论是小型的个人项目,还是大型的企业应用,Django都能游刃有余地满足需求。我们将从Django的基础知识带你全面掌握Django,从基础知识到高…...
“指标管理系统”是什么?企业如何搭建指标管理系统?
在当今数字化时代,数据已成为企业决策的重要依据。然而,海量数据中如何筛选出关键指标,并对其进行有效管理,成为了众多企业面临的难题。为此,指标管理系统应运而生,它旨在帮助企业规范化定义、统一管理和高…...
Node.js简单接口实现教程
Node.js简单接口实现教程 1. 准备工作 确保您的计算机已安装: Node.js (建议版本16.x以上)npm (Node包管理器) 2. 项目初始化 # 创建项目目录 mkdir nodejs-api-tutorial cd nodejs-api-tutorial# 初始化npm项目 npm init -y# 安装必要依赖 npm install expres…...
交换机四大镜像(端口镜像、流镜像、VLAN镜像、MAC镜像)应用场景、配置实例及区别对比
在网络管理中,端口镜像、流镜像、VLAN镜像和MAC镜像都是用于监控和分析网络流量的重要技术。 端口镜像(Port Mirroring) 定义:端口镜像是将一个或多个源端口的流量复制到一个目标端口,以便于网络管理员能够监控和分析…...
服务器上的常见Linux命令教程
在管理服务器(如香港服务器)时,掌握常见的 Linux 命令 是非常重要的,它们可以帮助你高效地完成服务器管理任务,如文件操作、进程管理、用户管理、网络配置等。 以下是一个系统化的 Linux 常见命令教程,分为…...
聚合支付系统/官方个人免签系统/三方支付系统稳定安全高并发 附教程
聚合支付系统/官方个人免签系统/三方支付系统稳定安全高并发 附教程 系统采用FastAdmin框架独立全新开发,安全稳定,系统支持代理、商户、码商等业务逻辑。 针对最近一些JD,TB等业务定制,子账号业务逻辑API 非常详细,方便内置…...
【MySQL】使用 JDBC 连接数据库
文章目录 前言1. 认识 JDBC 1.1 概念1.2 好处 2. 使用 JDBC 2.1 安装数据驱动包2.2 把 jar 包导入到项目中2.3 代码编写2.4 测试结果 3. 代码优化4. 源码展示结语 前言 在 MySQL 系列中,我们介绍了很多内容,包括但不限于建库建表,增删查改等…...
深入浅出:PHP会话管理(Session 和 Cookie)
深入浅出:PHP会话管理(Session 和 Cookie) 前言 在Web开发中,会话管理是确保用户状态持续性和数据安全的关键。通过会话管理,我们可以在多个页面请求之间保持用户的登录状态、购物车信息等。PHP提供了两种主要的会话…...
Logistic Regression(逻辑回归)、Maximum Likelihood Estimatio(最大似然估计)
Logistic Regression(逻辑回归)、Maximum Likelihood Estimatio(最大似然估计) 逻辑回归(Logistic Regression,LR)逻辑回归的基本思想逻辑回归模型逻辑回归的目标最大似然估计优化方法 逻辑回归…...
【开源】A063—基于Spring Boot的农产品直卖平台的设计与实现
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看项目链接获取⬇️,记得注明来意哦~🌹 赠送计算机毕业设计600个选题ex…...
单链表---合并两个链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 struct ListNode {int val;struct ListNode* next; }; w 方法一---不使用哨兵位 我们创建一个新链表用于合并两个升序链表, 将两个链表中最小的结点依次尾插到…...
draggable插件——实现元素的拖动排序——拖动和不可拖动的两种情况处理
最近在写后台管理系统的时候,遇到一个需求,就是关于拖动排序的功能。 我之前是写过一个关于拖动表格的功能,此功能可以实现表格中的每一行数据上下拖动实现排序的效果。 vue——实现表格的拖拽排序功能——技能提升 但是目前我这边的需求是…...
vite+vue3 配置ip和端口以及自动打开浏览器
编辑文件vite.config.ts 修改前vite.config.ts文件内容 import { defineConfig } from vite import vue from vitejs/plugin-vue// https://vite.dev/config/ export default defineConfig({plugins: [vue()], })修改vite.config.ts后文件内容 新增server内容 server:{host…...
Netty面试内容整理-Netty 概述
Netty 是一个基于 Java 的异步事件驱动网络应用框架,常用于构建高性能、高并发的网络服务。Netty 封装了 Java NIO 的复杂细节,使得开发者可以方便地构建高效的网络应用。以下是 Netty 的概述: Netty 的特点 ● 异步和事件驱动:Netty 采用异步非阻塞的 I/O 模型,基于事件驱…...
Docker搭建达梦数据库--基于 X86 架构
1、部署环境 X86_64 架构的服务器 1 台,安装好docker 拉取镜像 官方最新非授权版本有些函数方法无法使用 docker pull registry.cn-hangzhou.aliyuncs.com/qiluo-images/dm8_single:dm8_20230808_rev197096_x86_rh6_64查看镜像 docker images | grep dm8运行容器 docker run…...
4. 设计模式分类
4.1 创建型模式 这类模式提供创建对象的机制,能够提升已有代码的灵活性和可复用性。 序 号 类 型 业务场景 实现要点 1 工 厂 方 法 多种类型商品不同接口,统一发奖服 务搭建场景 定义一个创建对象的接口,让其子类自 己决定实例化哪一个工厂类,工厂模式 使其创建过程延迟…...
【SKFramework框架核心模块】3-12、网络请求模块
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群:398291828小红书小破站 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 【Unity3D框架】SKFramework框架完全教程《全…...
MacOS安装软件后无法启动报错:“已损坏,无法打开,你应该将它移到废纸篓“
目录 报错截图 解决方法 知识科普 报错截图 解决方法 1. 打开系统设置->安全性与隐私->选择任何来源 2. 如果打开没有看到"任何来源",如果不开启“任何来源”的选项,会直接影响到无法运行的第三方应用。开启“任何来源”的方法如下&a…...
每日速记10道java面试题14-MySQL篇
其他资料 每日速记10道java面试题01-CSDN博客 每日速记10道java面试题02-CSDN博客 每日速记10道java面试题03-CSDN博客 每日速记10道java面试题04-CSDN博客 每日速记10道java面试题05-CSDN博客 每日速记10道java面试题06-CSDN博客 每日速记10道java面试题07-CSDN博客 每…...
结构型-组合模式(Composite Pattern)
什么是组合模式 又名部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 结构 抽象根节点(Co…...
Netty面试内容整理-高级特性
Netty 提供了一些高级特性,使得它成为一个功能强大、灵活且适用于高并发、高性能场景的网络框架。以下是 Netty 的一些高级特性及其详细介绍: 零拷贝技术 ● 概念:零拷贝(Zero-Copy)是一种避免将数据从内核缓冲区复制到用户缓冲区的技术,从而减少内存拷贝,提高性能。 ●…...
【自动化】十款开源测试开发工具推荐自动化、性能、造数据、流量复制等
目录 一、AutoMeter-API 自动化测试平台二、QA Wolf 浏览器自动化测试工具三、Mimesis 用于 Python 的高性能虚假数据生成器四、Ddosify 高性能负载测试工具五、AutoCannon HTTP/1.1 基准测试工具六、Sharingan 流量录制回放工具七、randdata 随机测试数据生成工具八、Drission…...
【网络篇】HTTP知识
键入网址到网页显示,期间发生了什么? 浏览器第一步是解析URL,这样就得到了服务器名称和文件的路径名,然后根据这些信息生成http请求,通过DNS查询得到我们要请求的服务器地址,然后添加TCP头、IP头以及MAC头&…...
【飞牛云 fnos】 安装部署 Music Tag Web
在上一篇文章中,我们探讨了如何使用 Docker 和 Docker Compose 来部署 Music Tag Web。今天,我们将详细介绍如何在流行的 NAS 系统——飞牛云 FNOs 中安装 Music Tag Web,以便您能够轻松管理并丰富您的音乐库。 音乐刮削:让您的音…...
springmvc的简介
SpringMVC的介绍与第一个程序的开发步骤 1. 介绍 SpringMVC是一个实现了MVC架构模式的Web框架,底层基于Servlet实现。 SpringMVC已经将MVC架构模式实现了,因此只要我们是基于SpringMVC框架写代码,编写的程序就是符合MVC架构模式的。&#x…...
WordPress阅读文章显示太慢的处理
有两种方式, 1. 完全静态化。 尝试了几个插件,都未成功。算了放弃了。因为感觉到实际使用也不方便。 2. cache缓存 用了WP Super Cache测试了一下,打开过一次后,文章秒开,也算达到了要求。...
如何学习游戏外挂编程
学习游戏外挂编程需要掌握一定的编程基础和相关知识。以下是一些学习游戏外挂编程的步骤和建议: 学习编程基础:首先,你需要学习一种编程语言,比如C或者Python。了解基本的编程概念,如变量、函数、循环和条件语句等。这…...
AI大模型驱动数据分析:利用自然语言实现数据查询与可视化(1)
在当今AI驱动的时代,数据分析已成为各行各业不可或缺的能力。然而,传统的数据分析流程通常需要掌握SQL、数据处理和可视化等多项专业技能,这对非技术背景的业务人员来说是一个不小的挑战。 想象一下,当数据中心的负责人打开手机时…...
UE----Ios打包笔记
UE 打包 IOS 软件 1.前期准备 1.1. 首先我们需要 一台装有Xcode 的MAC笔记本(知道开机密码 最好是空的笔记本 剩余内存要大 ) 1.2. 一台IOS手机 1.3. 一个申请了开发者账户的 Apple ID (苹果账号) 知晓账号与密码最好 因为很麻烦 1.4. UE 需要 的 兼…...
Python_Flask03
这篇文章主要介绍的是数据库的增删改查操作,无多余好说的。 from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from flask_migrate import Migrateapp Flask(__name__)# 本地基础信息的主机名 HOSTNAME "127.0…...
PGSQL:联合唯一索引的创建和删除
创建联合唯一索引 假设有一个表 your_table,它有多个列,你想在其中的几列上创建一个联合唯一索引。以下是创建联合唯一索引的 SQL 语句: CREATE UNIQUE INDEX idx_unique_columns ON your_table(column1, column2, ...);注意: …...
QT5 Creator (Mingw编译器) 调用VS2019 (阿里云 oss C++库) 报错的解决方法
方法就是不要用VS2019编译,要用MINgw32编译。注意要安装高版本的qt,其自带的mingw编译器才能支持,找不到qt5cored.dll,就把qt5core.dll改名为qt5cored.dll。 编译命令如下: cmake -G "MinGW Makefiles" ^-…...
使用缓存提升Web应用性能:从新手到高手的实践指南
引言 在现代Web开发中,性能优化是确保用户体验和系统稳定性的关键。使用缓存是提升网站性能的有效手段之一,可以显著减少数据库访问和计算开销。根据“网站优化第一定律”,缓存可以提升网站的响应速度,减少延迟,从而改…...
详尽的oracle sql函数
1,CHR 输入整数,返回对应字符。 用法:select chr(65),chr(78) from dual; 2,ASCII 输入字符,返回对应ASCII码。 用法:select ascii(A),ascii(B) from dual; 3,CONCAT 输入两个字符串,…...
Unity 设计模式-策略模式(Strategy Pattern)详解
策略模式(Strategy Pattern)是一种行为型设计模式,定义了一系列算法,并将每种算法封装到独立的类中,使得它们可以互相替换。策略模式让算法可以在不影响客户端的情况下独立变化,客户端通过与这些策略对象进…...
AI Agent重塑微服务治理
导读 随着技术架构的发展,微服务系统的复杂性不断增加,对运维提出了更高的要求。为了应对这一挑战,一种AI驱动的微服务治理方案被提出。该方案采用多智能体架构,将运维专家经验整合,并通过自然语言交互和智能推理&…...
SpringBoot整合knife4j,以及会遇到的一些bug
这篇文章主要讲解了“Spring Boot集成接口管理工具Knife4j怎么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Boot集成接口管理工具Knife4j怎么用”吧! 一…...
vue自定义组件双向数据绑定
1、使用v - model指令(推荐方式)2、手动实现双向绑定(不使用v - model语法糖)3、 .sync修饰符4、.sync 与 v - model 的比较 1、使用v - model指令(推荐方式) 在 Vue 中,v - model是一个语法糖…...
【Linux课程学习】:想对Linux说的话
🎁个人主页:我们的五年 🔍系列专栏:Linux课程学习 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 一.Linux学习存在的问题: 二.Linu…...