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

C++ 语言特性29 - 协程介绍

一:什么是协程

        C++20 引入了协程(coroutine),这是 C++ 标准库中一个强大的新特性。协程是一种可以在执行中暂停并随后恢复的函数,允许程序在异步或并行场景下高效管理任务,而不需要传统的线程或复杂的回调机制。

        协程是可以暂停其执行并保存其当前状态,稍后可以从该位置恢复执行的特殊函数。在某种程度上,协程类似于普通函数,但它们的执行流可以通过 co_awaitco_yieldco_return 来暂停和恢复。这与传统函数的行为不同,传统函数一旦开始执行,就会一直运行到返回或退出为止。

        协程与线程的不同在于,协程不会引入新的线程,它们是在现有线程上执行的。协程的切换开销通常非常低,远小于线程切换,因此在处理高并发场景下具有很大的优势。

二:协程的语法

     C++20 协程的语法引入了三种关键字:

  1. co_return:从协程中返回值。
  2. co_yield:暂停协程,并返回一个值给调用者,稍后可以恢复协程。
  3. co_await:暂停协程,等待某个异步操作完成后再继续执行。

        为了使用协程,C++ 中的一个普通函数必须返回某种特殊的类型,而不是像 void 或普通类型那样。这个特殊的返回类型需要符合协程的约定,它定义了如何控制协程的生命周期。下面举一个例子,演示下协程的使用:

#include <iostream>
#include <coroutine>
#include <thread>
#include <chrono>// 一个简单的协程返回对象类型
struct Task {struct promise_type {Task get_return_object() {return Task{std::coroutine_handle<promise_type>::from_promise(*this)};}std::suspend_never initial_suspend() { return {}; }  // 协程立即开始执行std::suspend_always final_suspend() noexcept { return {}; } // 协程结束时暂停void return_void() {}void unhandled_exception() { std::terminate(); }};std::coroutine_handle<promise_type> handle;Task(std::coroutine_handle<promise_type> h) : handle(h) {}~Task() { handle.destroy(); }void resume() { handle.resume(); }
};// 一个自定义的 awaitable 类型,用于模拟异步任务
struct Awaiter {bool await_ready() { return false; } // 表示协程需要挂起void await_suspend(std::coroutine_handle<>) {// 模拟异步任务的延迟,例如 I/O 操作std::this_thread::sleep_for(std::chrono::seconds(1));}void await_resume() {}
};// 协程函数,模拟异步任务
Task async_task() {std::cout << "Task started, waiting for 1 second...\n";co_await Awaiter{};  // 挂起协程并等待模拟异步任务std::cout << "Task resumed after 1 second!\n";
}int main() {Task task = async_task();task.resume();  // 启动协程std::cout << "Main function continues execution...\n";
}

上面代码中主要变量和函数如下; 

  • 协程句柄 (std::coroutine_handle)

    std::coroutine_handle 是一个可以用来控制协程生命周期的类型。它可以暂停、恢复协程以及销毁协程。std::coroutine_handle 提供了一些常用的成员函数,例如 resume()destroy() 等,用于管理协程的执行。

  • Promise 对象

    每个协程都有一个与之关联的 promise 对象(promise_type)。它负责管理协程的状态和返回值。promise_type 需要实现一些特定的函数,比如 get_return_object()(返回协程的返回对象)、initial_suspend()(定义协程开始时的行为)和 final_suspend()(定义协程结束时的行为)。

  • 挂起点 (co_await)

    co_await 是协程的核心,它允许协程暂停执行,等待某个条件满足时恢复。co_await 的行为依赖于其后跟随的对象或表达式,它可以是等待一个异步操作完成,也可以是一个延迟或其他触发条件。

    协程的暂停和恢复类似于保存函数的状态,并在以后恢复它的执行,这样可以避免使用回调或复杂的状态机来处理异步操作

  • 协程函数 async_task

    • 使用 co_await 关键字等待 Awaiter 类型,这会暂停协程,并在一秒钟后恢复。
    • 恢复后,协程继续执行并打印消息。
  • 自定义的 Awaiter

    • await_ready 返回 false,表明协程需要挂起。
    • await_suspend 中使用 std::this_thread::sleep_for 来模拟一个异步任务(实际情况中可以是 I/O 操作或其他异步任务)。
    • await_resume 恢复协程。
  • main 函数

    • 调用 async_task 来创建协程对象 task,并使用 resume 来启动协程。

 这个例子运行过程如下:

  • 协程开始执行,打印 Task started, waiting for 1 second...,然后协程挂起 1 秒钟。
  • 主函数继续执行并打印 Main function continues execution...
  • 1 秒钟后,协程恢复执行并打印 Task resumed after 1 second!

三:协程的使用场景

1. 异步 I/O 操作

      在传统的同步代码中,I/O 操作(如网络或磁盘操作)通常会阻塞线程,导致线程空闲等待。在 C++ 中使用协程,可以使得这些 I/O 操作异步化,协程可以在 I/O 操作完成时继续执行,而不阻塞整个线程。在这个例子中,协程 sleep_one_second 会暂停执行 1 秒,然后恢复。

#include <iostream>
#include <chrono>
#include <thread>
#include <coroutine>struct Sleeper {struct promise_type {Sleeper get_return_object() { return {}; }std::suspend_always initial_suspend() { return {}; }std::suspend_always final_suspend() noexcept { return {}; }void return_void() {}void unhandled_exception() { std::terminate(); }};bool await_ready() { return false; }void await_suspend(std::coroutine_handle<>) {std::this_thread::sleep_for(std::chrono::seconds(1));}void await_resume() {}
};Sleeper sleep_one_second() {std::cout << "Sleeping..." << std::endl;co_await Sleeper{};std::cout << "Awake!" << std::endl;
}
2. 生成器

协程可以用来实现生成器模式,允许在迭代过程中动态生成值,而不需要一次性返回整个集合。这个例子中的 range 协程会生成一个从 0 到 4 的整数序列,类似于 Python 的生成器。

#include <iostream>
#include <coroutine>
#include <vector>struct Generator {struct promise_type {int current_value;Generator get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; }std::suspend_always initial_suspend() { return {}; }std::suspend_always final_suspend() noexcept { return {}; }std::suspend_always yield_value(int value) {current_value = value;return {};}void return_void() {}void unhandled_exception() { std::terminate(); }};std::coroutine_handle<promise_type> handle;Generator(std::coroutine_handle<promise_type> h) : handle(h) {}~Generator() { if (handle) handle.destroy(); }bool move_next() {handle.resume();return !handle.done();}int current_value() { return handle.promise().current_value; }
};Generator range(int start, int end) {for (int i = start; i < end; ++i) {co_yield i;}
}int main() {auto gen = range(0, 5);while (gen.move_next()) {std::cout << gen.current_value() << " ";}
}

四:协程的优势

  1. 简化异步代码:协程可以以同步风格编写异步代码,简化了复杂的异步操作,如异步 I/O、网络通信、文件读写等。
  2. 高性能:协程切换的开销通常比线程上下文切换低,因此在高并发场景下协程更为高效。
  3. 提高代码可读性:协程使得代码更加线性和易读,避免了大量嵌套的回调或状态机逻辑。

 

相关文章:

C++ 语言特性29 - 协程介绍

一&#xff1a;什么是协程 C20 引入了协程&#xff08;coroutine&#xff09;&#xff0c;这是 C 标准库中一个强大的新特性。协程是一种可以在执行中暂停并随后恢复的函数&#xff0c;允许程序在异步或并行场景下高效管理任务&#xff0c;而不需要传统的线程或复杂的回调机制。…...

[Day 84] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

AI在公共安全中的應用實例 引言 隨著技術的進步&#xff0c;人工智能&#xff08;AI&#xff09;在公共安全領域的應用越來越廣泛。AI不僅能夠提高安全部門的工作效率&#xff0c;還能有效幫助預防和處理各類公共安全事件。從人臉識別、行為分析到災害預測&#xff0c;AI正在…...

八大排序--01冒泡排序

假设有一组数据 arr[]{2&#xff0c;0&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;7} 方法&#xff1a;开辟两个指针&#xff0c;指向如图&#xff0c;前后两两进行比较&#xff0c;大数据向后冒泡传递&#xff0c;小数据换到前面。 一次冒泡后&#xff0c;数组中最大…...

【Kubernetes】常见面试题汇总(五十)

目录 112.考虑一个公司要向具有各种环境的客户提供所有必需的分发产品的方案。您如何看待他们如何动态地实现这一关键目标&#xff1f; 113.假设一家公司希望在从裸机到公共云的不同云基础架构上运行各种工作负载。在存在不同接口的情况下&#xff0c;公司将如何实现这一目标&…...

Linux 操作系统中的 main 函数参数和环境变量

在聊进程替换之前&#xff0c;有一些基础知识我们得先弄清楚。掌握了这些内容&#xff0c;不仅能让你更轻松地理解 Shell 是如何工作的&#xff0c;还能为之后的进程替换操作铺好路。进程替换说白了就是 Shell 的基本原理&#xff0c;它能把一个命令的输出直接当成另一个命令的…...

Vue项目中通过插件pxtorem实现大屏响应式

一、原理 rem单位代表的是根节点的font-size大小&#xff0c;所以当我们在页面上使用rem去替代px的时候&#xff0c;就可以通过修改根节点font-size的值&#xff0c;动态地让页面上的元素根据不同浏览器宽高下去实现变化。 二、工具 1.postcss-pxtorem 作用&#xff1a;在编…...

(Django)初步使用

前言 Django 是一个功能强大、架构良好、安全可靠的 Python Web 框架&#xff0c;适用于各种规模的项目开发。它的高效开发、数据库支持、安全性、良好的架构设计以及活跃的社区和丰富的文档&#xff0c;使得它成为众多开发者的首选框架。 目录 安装 应用场景 良好的架构设计…...

【星汇极客】单片机竞赛之2024睿抗机器人大赛-火线速递赛道(持续更新)

前言 本人是一名嵌入式学习者&#xff0c;在大学期间也参加了不少的竞赛并获奖&#xff0c;包括但不限于&#xff1a;江苏省电子设计竞赛省一、睿抗机器人国二、中国高校智能机器人国二、嵌入式设计竞赛国三、光电设计竞赛国三、节能减排竞赛国三。 后面会经常写一下博客&…...

生信科研,教授(优青)团队一站式指导:高通量测序技术--农业植物基因组分析、组蛋白甲基化修饰、DNA亲和纯化测序、赖氨酸甲基化

组蛋白甲基化修饰工具(H3K4me3 ChIP-seq) 组蛋白甲基化类型也有很多种&#xff0c;包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守&#xff0c;是被研究最多的组蛋白修饰之一。 DNA亲和纯化测序 DNA亲…...

【Immich部署与访问】自托管媒体文件备份服务 Immich 本地化部署与远程访问存储数据

文章目录 前言1.关于Immich2.安装Docker3.本地部署Immich4.Immich体验5.安装cpolar内网穿透6.创建远程链接公网地址7.使用固定公网地址远程访问 前言 本篇文章介绍如何在本地搭建lmmich图片管理软件&#xff0c;并结合cpolar内网穿透实现公网远程访问到局域网内的lmmich&#…...

AI少女/HS2甜心选择2 仿逆水寒人物卡全合集打包

内含AI少女/甜心选择2 仿逆水寒角色卡全合集打包共6张 内含&#xff1a;白灵雪魅落霞飞雁君临华歌白君临华歌黑平野星罗晚香幽韵 下载地址&#xff1a; https://www.51888w.com/436.html 部分演示图&#xff1a;...

C/C++逆向:数据类型识别

在逆向工程中&#xff0c;数据类型识别是理解程序逻辑的重要步骤&#xff0c;因为它直接影响对程序逻辑和功能的理解&#xff0c;识别出数据类型有助于确定变量的含义和函数的行为。在分析恶意软件或者寻找安全漏洞时&#xff0c;识别数据类型能够帮助发现代码中的潜在问题。例…...

PASCAL VOC 2012数据集 20类物体,这些物体包括人、动物(如猫、狗、鸟等)、交通工具(如车、船、飞机等)以及家具(如椅子、桌子、沙发等)。

VOC2012数据集是PASCAL VOC挑战赛官方使用的数据集之一&#xff0c;主要包含20类物体&#xff0c;这些物体包括人、动物&#xff08;如猫、狗、鸟等&#xff09;、交通工具&#xff08;如车、船、飞机等&#xff09;以及家具&#xff08;如椅子、桌子、沙发等&#xff09;。每个…...

题目:最左边的数字

问题 - 1060 (hdu.edu.cn) 解题思路&#xff1a; 数字很大&#xff0c;使用科学计数法。则&#xff0c;我们需要的是a的整数位&#xff0c;最终求出a即可。 取对数&#xff1a;nlgnmlga&#xff0c;移项&#xff1a;lganlgn-m&#xff0c;接下来我们需要求m。 …...

第 4 章 Spring IoC容器之BeanFactory

Spring 的 IoC 容器是一个提供 IoC 支持的轻量级容器&#xff0c;除了基本的 IoC 支持&#xff0c;它作为轻量级容器还提供了 IoC 之外的支持。 Spring 提供了两种容器类型&#xff1a;BeanFactory 和 ApplicationContext&#xff1a; BeanFactory&#xff0c;基础类型 IoC 容…...

滚雪球学Oracle[2.3讲]:Oracle Listener配置与管理

全文目录&#xff1a; 前言一、Oracle Listener的基础概念1.1 什么是Oracle Listener&#xff1f;Listener的作用&#xff1a; 1.2 Oracle Listener的配置文件示例listener.ora配置文件&#xff1a; 1.3 启动与管理Listener 二、多Listener配置与负载分担2.1 多Listener的应用场…...

免费送源码:Javaspringboot++MySQL springboot 社区互助服务管理系统小程序 计算机毕业设计原创定制

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受居民的喜爱&#xff0c;社区互助服务管理系统小程序被居民普遍使用&#xff0c;为…...

成都睿明智科技有限公司抖音电商新蓝海的领航者

在当今这个数字化浪潮汹涌的时代&#xff0c;电商行业正以惊人的速度迭代升级&#xff0c;而抖音电商作为新兴势力&#xff0c;更是凭借其庞大的用户基数、精准的算法推荐和高度互动的社区氛围&#xff0c;成为了众多商家竞相追逐的蓝海市场。在这片充满机遇与挑战的海洋中&…...

不可错过!CMU最新《生成式人工智能大模型》课程:从文本、图像到多模态大模型

1. 课程简介 从生成图像和文本到生成音乐和艺术&#xff0c;生成模型一直是人工智能的关键挑战之一。本课程将探讨推动生成模型和基础模型&#xff08;Foundation Models&#xff09;最近进展的机器学习和人工智能技术。学生将学习、开发并应用最先进的算法&#xff0c;使机器…...

重庆数字孪生工业互联网可视化技术,赋能新型工业化智能制造工厂

重庆作为西南地区的重要工业基地&#xff0c;正积极探索和实践数字孪生、工业互联网及可视化技术在智能制造领域的深度融合&#xff0c;致力于打造新型工业化智能制造工厂&#xff0c;为制造业的高质量发展注入强劲动力。 在重庆的智能制造工厂中&#xff0c;数字孪生技术被广…...

Qt QPushButton clicked信号浅析

前言 Qt 的 QPushButton clicked 信号原型&#xff1a; void clicked(bool checked false);通常&#xff0c;使用 Qt 的 QPushButton clicked 点击信号时&#xff0c;会以如下方式使用&#xff1a; connect(ui->pushButton, &QPushButton::clicked, this, [](){qDeb…...

Python时间戳转日期

在Python中&#xff0c;你可以使用datetime模块将时间戳转换为日期。时间戳通常是一个表示自1970年1月1日&#xff08;UTC&#xff09;以来的秒数的浮点数或整数。 以下是一个简单的示例&#xff0c;展示了如何将时间戳转换为日期和时间&#xff1a; import datetime# 示例时…...

对 LLM 工具使用进行统一

我们为 LLM 确立了一个跨模型的 统一工具调用 API。有了它&#xff0c;你就可以在不同的模型上使用相同的代码&#xff0c;在 [Mistral] 或 [Llama]) 等模型间自由切换&#xff0c;而无需或很少需要根据模型更改工具调用相关的代码。此外&#xff0c;我们还在 transformers 中新…...

webpack/vite的区别

Webpack和Vite都是前端开发中常用的构建工具&#xff0c;它们在多个方面存在显著的区别。以下是对这两个构建工具的详细比较&#xff1a; 一、基础概念与定位 Webpack Webpack是一个现代JavaScript应用程序的静态模块打包器&#xff08;module bundler&#xff09;。它允许开发…...

【笔记】信度检验

一、信度 信度是指测量结果的一致性和稳定性。 1.一致性&#xff08;Consistency&#xff09; 一致性指的是测量工具内部各个部分或项目之间的协调一致程度。高一致性意味着测量工具的不同部分都在测量同一个概念或特质。 例子&#xff1a;智力测试 假设我们有一个包含100…...

使用Python实现无人机路径规划的灰狼优化算法

目录 使用 Python 实现无人机路径规划的灰狼优化算法引言1. 灰狼优化算法概述1.1 定义1.2 算法原理1.3 灰狼的狩猎策略1.4 算法步骤 2. Python 中的灰狼优化算法实现2.1 安装必要的库2.2 定义类2.2.1 灰狼类2.2.2 群体类2.2.3 路径规划类 2.3 示例程序 3. 灰狼优化算法的优缺点…...

理解递归和回溯

文章目录 什么是递归回溯 什么是递归 回溯 //使用递归回溯来给小球找路//说明//1. map 表示地图//2. i,j 表示从地图的哪个位置开始出发 (1,1)//3. 如果小球能到 map[6][5] 位置&#xff0c;则说明通路找到.//4. 约定&#xff1a; 当map[i][j] 为 0 表示该点没有走过 当为 1 表…...

知识图谱入门——3:工具分类与对比(知识建模工具:Protégé、 知识抽取工具:DeepDive、知识存储工具:Neo4j)

在知识图谱构建的过程中&#xff0c;针对不同的任务和需求&#xff0c;我们可以使用多种工具。为了帮助你快速选择合适的工具&#xff0c;本文将常用工具按类别进行分类介绍&#xff0c;并对比其优缺点&#xff0c;方便你在不同场景中做出最佳选择。 文章目录 1. 知识建模工具…...

使用指标进行量化交易时,有哪些需要注意的风险点呢

炒股自动化&#xff1a;申请官方API接口&#xff0c;散户也可以 python炒股自动化&#xff08;0&#xff09;&#xff0c;申请券商API接口 python炒股自动化&#xff08;1&#xff09;&#xff0c;量化交易接口区别 Python炒股自动化&#xff08;2&#xff09;&#xff1a;获取…...

数据结构阶段测试2的一点小补充

数据结构阶段测试2的一点小补充 1.已知⼩根堆为8,15,10,21,34,16,12&#xff0c;删除关键字8之后需重建堆&#xff0c;最后的叶⼦ 节点为() A. 34 B. 21 C. 16 D. 12 解题思路 向下调整算法删除堆顶元素 &#x1f4a1; 答案&#xff1a;C 删除堆顶元素的思路&#xff1a; …...