0

0

c++如何用Coroutines实现一个异步生成器_c++ co_yield应用实例【C++20】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-12-15 11:05:15

|

466人浏览过

|

来源于php中文网

原创

c++kquote>C++20协程通过co_yield实现懒求值生成器,核心是自定义generator返回类型及promise_type;同步示例为斐波那契数列,异步需结合co_await定时或IO操作;注意生命周期、编译选项及标准支持差异。

c++如何用coroutines实现一个异步生成器_c++ co_yield应用实例【c++20】

在 C++20 中,协程(Coroutines)支持异步生成器模式,核心是通过 co_yield 暂停执行并产出值,配合自定义的协程返回类型(如 generator)实现懒求值、按需生成的迭代器行为。它不是“异步 I/O”意义上的 async/await(那需要 executor 和 awaitable),而是“异步生成”——即调用方可以一边取值、一边让生成逻辑在后台(或分步)计算,不阻塞主线程。

1. 用 std::generator(C++26 草案)或手动实现 generator

C++20 标准库并未提供 generator,但 MSVC 和 libc++ 已实验性支持 std::generator(C++26 提案 P2471)。若用 GCC 或需跨平台兼容,推荐手动实现一个轻量 generator,重点在于:

  • 定义协程返回类型(含 promise_type
  • promise_type::get_return_object() 返回 generator 实例
  • promise_type::yield_value(T&& v) 保存当前值并挂起
  • generator 自带迭代器接口(begin()/end()),内部用 coroutine_handle 控制恢复

2. 基础同步生成器:斐波那契数列示例

这是理解 co_yield 最直观的例子——每次调用 ++it 触发一次恢复,产出下一个数:

generator fib(int n) {
    int a = 0, b = 1;
    co_yield a;
    if (n <= 1) co_return;
    co_yield b;
    for (int i = 2; i < n; ++i) {
        int next = a + b;
        co_yield next;
        a = b;
        b = next;
    }
}

// 使用:
for (int x : fib(10)) {
    std::cout << x << " "; // 0 1 1 2 3 5 8 13 21 34
}

注意:co_yield 自动调用 promise_type::yield_value 并 suspend;co_return 结束协程。整个过程是同步的(无线程/await),但“按需生成”特性已具备。

立即学习C++免费学习笔记(深入)”;

Sologo AI
Sologo AI

SologoAI 是一款AI在线LOGO生成工具,帮助用户快速创建独特且专业的品牌标识和配套VI设计。

下载

3. 真正的异步生成器:结合 awaitable + 定时/IO 操作

要让生成器“异步”,需在 co_yield 前插入可等待操作(例如延迟、网络读取)。关键点:

  • 协程函数返回类型必须是 awaitable(如 task 或自定义 awaitable)
  • co_yield 仍用于产出值,但协程可在 yield 前 co_await sleep_for(...) 等待
  • 产出值后协程挂起,控制权交还调度器;下次被 resume 时继续执行下一轮

示例:每秒产出一个递增数字(模拟异步数据流):

task ticker(generator::push_type push) {
    for (int i = 0; ; ++i) {
        co_await std::experimental::suspend_until(
            std::chrono::steady_clock::now() + 1s);
        co_yield i; // 产出给 push(需 generator 支持 push 模式)
    }
}

⚠️ 注意:标准 generator 是 pull-based(调用方驱动),若要 push-based(生产者驱动+回调),需自己设计 push_type 或用 channel(如 libunifex 或 cppcoro)。

4. 实用建议与避坑点

  • co_yield 只能在协程函数中使用,且函数返回类型必须有合适的 promise_type
  • 避免在 co_yield 后访问已移动或局部销毁的对象(yield 是 suspend,帧保留,但局部对象生命周期仍按作用域结束)
  • 调试协程较难,建议先写同步版验证逻辑,再加 co_await
  • GCC 12+ / Clang 16+ / MSVC 19.30+ 对 C++20 协程支持较完整;编译需加 -std=c++20 -fcoroutines(GCC/Clang)或 /std:c++20 /await(MSVC)

基本上就这些。用 co_yield 实现生成器本质是“用户态协作式迭代”,是否“异步”取决于你是否在里面 co_await 了真正异步的操作。它不复杂但容易忽略 promise_type 的细节和生命周期管理。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1072

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

127

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

826

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

13

2026.01.19

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

574

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

25

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
ASP 教程
ASP 教程

共34课时 | 4万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2万人学习

550W粉丝大佬手把手从零学JavaScript
550W粉丝大佬手把手从零学JavaScript

共1课时 | 0.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号