协程的承诺——C++20中最复杂特性的设计故事

简介: C++20引入了协程,这被认为是自C++11以来最复杂的语言特性,甚至比模板元编程和移动语义更难掌握。

C++20引入了协程,这被认为是自C++11以来最复杂的语言特性,甚至比模板元编程和移动语义更难掌握。协程的提案和标准化过程历时多年,经历了多次重大修改,最终版本充满了抽象概念和新的关键字。理解协程为什么被设计成这个样子,需要回顾它的目标、约束、以及与其他语言协程实现的比较。

协程的基本思想是函数可以挂起和恢复。普通的函数调用后,控制权完全交给被调函数,直到它返回;而协程可以在执行到某个点时主动让出控制权(挂起),然后在稍后的某个时间点从挂起点恢复执行。这种能力对于异步编程、生成器、流处理、以及状态机等模式至关重要。在C++20之前,实现异步代码的传统方式是回调地狱:发起一个异步操作,传入一个回调函数,操作完成后调用回调。这种模式在简单场景下可行,但随着嵌套层数增加,代码变得难以阅读和维护。Promise-Future模式在一定程度上缓解了这个问题,但仍然需要显式管理状态。协程承诺将异步代码写成同步风格,让编译器自动处理挂起和恢复的底层机制。
参考:https://oqmyh.cn/category/mingan-huli.html

C++协程的设计面临三个核心约束:
零开销原则:协程的挂起和恢复不应该比等价的回调代码慢。这意味着协程的状态不能在堆上随意分配,必须尽可能紧凑,并且上下文切换的成本必须极低。
与现有C++代码的兼容性:协程必须能够调用普通函数,普通函数也必须能够调用协程。协程不能要求特殊的运行时或垃圾回收。
灵活性:协程应该能够用于多种场景:生成器(yield值)、异步任务(返回future)、惰性求值、以及自定义的状态机。

这些约束共同塑造了C++协程的独特设计。与Python或JavaScript中协程是语言核心的一部分不同,C++协程是库设施——语言只提供了底层机制,而具体的行为由库实现者通过一组约定来定义。
参考:https://oqmyh.cn/category/kang-shuailao.html

C++协程的核心概念有三个:协程句柄、承诺对象和挂起点。

协程句柄是一个非拥有型的句柄,用于恢复协程或查询协程的状态。它类似于指针,但设计为不拥有协程帧的内存(协程帧包含协程的状态,如局部变量和挂起点)。协程句柄可以在协程外部使用,允许外部代码恢复协程或销毁协程。

承诺对象是协程的控制面。它定义了协程的行为:当协程挂起时应该发生什么?当协程返回一个值时应该发生什么?当协程抛出异常时应该发生什么?协程的返回类型决定了承诺对象的类型——编译器通过std::coroutine_traits来查找承诺类型。这种设计使得同一个协程语言机制可以用于多种场景:对于生成器,承诺对象实现yield_value方法;对于异步任务,承诺对象实现await_transform和unhandled_exception。

挂起点是协程中co_await、co_yield和co_return出现的位置。co_await是最通用的挂起机制,它等待一个可等待对象。可等待对象必须实现await_ready(是否已经就绪)、await_suspend(挂起时做什么)和await_resume(恢复时返回什么)这三个方法。这种设计允许库作者自定义挂起和恢复的行为——例如,挂起时可以将协程句柄添加到事件循环中,等待IO完成后再恢复。

co_yield是co_await的特化,用于生成器场景:它将一个值产出给调用者,然后挂起。co_return表示协程完成,类似于普通函数的return。
参考:https://oqmyh.cn/category/hufu-chengfen.html

C++协程设计中最有争议的部分是对称转移(symmetric transfer)。考虑一个协程A等待协程B的情况:当B完成时,控制权应该转移到A。在对称转移的支持下,B可以直接恢复A,而不需要通过外部调度器。C++20最初没有强制要求对称转移,这导致某些实现需要额外的内存分配和调度器调用。C++23引入了std::coroutine_handle::resume的对称版本,但编译器支持尚不普遍。

协程的内存分配是另一个性能关键点。每个协程实例需要一个帧来存储局部变量和挂起状态。编译器会计算帧的大小,然后调用operator new分配内存。对于频繁创建和销毁的协程,内存分配的成本可能很高。优化策略包括:使用自定义分配器、对帧进行池化、以及利用返回值优化(如果协程的状态可以嵌入到调用者的帧中)。C++23引入了对协程帧使用自定义分配器的标准支持。

协程与RAII的交互值得特别注意。协程的局部变量在挂起期间仍然存活,这意味着如果协程持有一个RAII资源(如锁或文件句柄),该资源会在整个挂起期间保持占用,可能导致死锁或资源耗尽。开发者在设计协程时需要注意这一点,避免在挂起点持有锁或其他独占资源。

协程的调试比普通函数困难得多。在挂起点处,协程的栈帧不是完整的——部分状态存储在协程帧中,部分在调用者的栈上。这使得传统的栈回溯工具无法显示协程的完整调用链。一些调试器(如最新版本的GDB和LLDB)已经添加了对协程的部分支持,但体验仍然远不如普通函数。

协程的标准化只是第一步。真正的变革将来自基于协程构建的库和运行时。例如:
std::generator(C++23)提供了一个标准的生成器协程类型,用于惰性序列。
异步IO库(如boost::asio、cppcoro)提供了与事件循环集成的可等待对象。
并发任务框架允许协程在不同线程上执行,并在完成时恢复。

与Rust的async/await相比,C++的协程设计更加底层和灵活。Rust的异步机制完全依赖于运行时(如Tokio),而C++协程可以在任何环境下工作,包括嵌入式系统和无分配的环境。这种灵活性是以复杂性为代价的——Rust开发者通常只需要写async fn和.await,而C++开发者需要理解承诺对象、协程句柄和可等待协议的细节。

对于大多数C++开发者来说,直接使用协程的原始机制是不明智的。更好的做法是使用已经封装好的协程库,只在必要的时候深入到底层。随着C++23和C++26对协程的完善,以及社区积累的最佳实践,协程的编程模型将逐渐变得更加友好和直观。
参考:https://oqmyh.cn

目录
相关文章
|
14天前
|
缓存 NoSQL 网络协议
如何为我的网站或应用集成IP归属地查询功能?
本文为网站/应用集成IP归属地查询的落地指南:强调“取对IP”是前提(仅信可信上游、严滤私网),采用“本地+Redis缓存+在线API+硬超时熔断”架构,失败自动降级至省/国家;区分展示型与风控型模型,确保可解释、可审计、可回滚,并严守隐私合规红线。(239字)
153 13
|
10天前
|
数据采集 缓存 运维
IP查询工具如何评估IP负载?云上资源分配的实战方法
我们曾因P99延迟骤升盲目扩容无效,最终靠IP分桶定位到某云厂商ASN段的爬虫流量。IP查询工具不测性能,而是为请求打标签(ASN/代理类型/风险分等),结合监控数据精准识别“谁拖垮了系统”。分四类桶、设三条件、按优先级调度(分流>限流>扩容>封禁),离线缓存+二次验证,避免误伤。
|
28天前
|
新零售 移动开发 运维
直播带货平台开发需要多少钱?电商直播系统源码方案解析
直播电商爆发式增长,自建平台成新零售刚需。本文解析开发成本构成:直播技术、电商系统、管理后台三大模块;对比自研、定制、源码采购三种模式,成本从百万级降至数万元;强调稳定性、高并发与扩展性等关键技术能力,助力企业高效入局。
|
28天前
|
人工智能 自然语言处理 前端开发
AI龙虾必备:4个做短视频的Agent Skills
AI龙虾必备:4个做短视频的Agent Skills
|
2月前
|
存储 安全 Java
你还在手动传包、靠“共享盘”发版本?Artifact Registry 才是依赖管理的终局答案!
你还在手动传包、靠“共享盘”发版本?Artifact Registry 才是依赖管理的终局答案!
382 16
|
1月前
|
机器学习/深度学习 搜索推荐 数据处理
PAI-Rec推荐开发平台:企业级智能推荐解决方案,驱动业务全域增长
PAI-Rec是阿里云一站式推荐系统平台,集成多路召回、多目标精排(如DBMTL)、GPU加速推理与灵活迭代能力,已助力电商、直播、音视频等多行业提升点击率、转化率与ROI,实现高效、低成本、可自主演进的智能推荐。
256 16
|
2月前
|
人工智能 自然语言处理 API
阿里云轻量服务器部署OpenClaw|iMessage一键接入+千问/Coding Plan API+避坑指南
2026年,AI自动化框架OpenClaw(原Clawdbot)凭借阿里云轻量服务器低成本、高稳定的部署优势,搭配iMessage深度集成能力,成为连接苹果生态与云端AI的高效工具。轻量服务器提供OpenClaw官方预置镜像,无需手动配置环境,3分钟即可完成云端部署;接入阿里云千问大模型、免费Coding Plan API后,可通过iMessage实现iPhone、Mac、iPad与云端AI的双向交互,满足个人效率管理、移动AI助手、轻量业务自动化等场景需求。
335 9
|
28天前
|
存储 数据采集 人工智能
2026年企业级BI系统建设方案:从数据孤岛到湖仓一体
在数字化转型深水区,数据孤岛严重制约价值释放。2026年企业级BI建设聚焦“湖仓一体”:以统一数据底座、全链路治理、AI原生分析为核心,打通系统壁垒、统一口径标准、激活全域数据,构建高可靠、全员可用的智能决策中枢。(239字)
|
2月前
|
Python
5个提升Python效率的实用技巧
5个提升Python效率的实用技巧
118 17
|
2月前
|
人工智能 安全 IDE
多模型自由切换,研发效率再升级实战干货
不是简单的AI补全,而是完整的「研发全流程支撑体系」,把「环境、协作、AI、安全」四大核心模块打包整合,形成可直接落地的实操体系。很多之前要手动折腾半天的事,现在能交给系统自动完成。本篇结合真实使用场景,从认知、核心能力、实战案例到使用心得,把实操细节、踩过的坑和效率提升点一次性说透。