现代 C++ 实战(27):协程与 Actor 模型
第 26 篇 的两个练手项目收尾了数据结构;系列最后一篇进入现代 C++ 的两条并发进阶路线:C++20 协程让异步代码像同步一样写,Actor 模型让并发像发消息一样简单。
demo:ref/cpp_demo/projects/learning_guide/(coroutine/ + actor/)。
这是「现代 C++ 实战」系列的第 27 篇(收官)。建议先读 第 12 篇:多线程基础 和 第 14 篇:线程池。
一、协程基础:三个关键字
C++20 协程用编译器魔法把异步逻辑写成顺序代码:
| 关键字 | 作用 | 示例 |
|---|---|---|
co_yield |
产生一个值并挂起 | Generator |
co_await |
等待异步操作完成 | Task |
co_return |
协程返回 | 结束协程 |
1 | Generator<int> counter(int max) { |
协程底层三件套:
| 概念 | 说明 |
|---|---|
promise_type |
定义协程行为(挂起策略、返回值处理) |
coroutine_handle |
协程句柄,恢复/销毁 |
| 返回类型 | 必须包含 promise_type(如 Generator<T>) |
二、Generator:惰性序列
Generator 是惰性的——只在迭代时才计算下一个值:
1 | Generator<int> fibonacci(int count) { |
demo 提供函数式组合,类似 Ranges 管道:
1 | // 取前 5 个偶数的平方 |
| 操作 | 作用 |
|---|---|
map(gen, fn) |
变换每个元素 |
filter(gen, pred) |
过滤 |
take(gen, n) |
取前 n 个 |
三、Task:异步任务
Generator 用 co_yield;异步 I/O 用 co_await:
1 | Task<int> async_compute() { |
Task + Scheduler 实现协作式多任务:
1 | 主协程 ──co_await──> 挂起 |
C++23 的 std::generator 是标准库版 Generator;Task 仍需自定义或使用第三方库(cppcoro、libunifex)。
四、Actor 模型概念
不要共享状态,通过消息传递。
1 | Actor A Actor B |
| 概念 | 说明 |
|---|---|
| Actor | 独立实体,拥有自己的状态 |
| Mailbox | 线程安全消息队列 |
| Message | 类型安全的消息(std::variant) |
| ActorRef | Actor 的引用,用于发送消息 |
| ActorSystem | 管理 Actor 生命周期 |
每个 Actor 单线程处理自己的邮箱——无锁共享状态,避免数据竞争。
五、Actor 实现要点
Mailbox:线程安全队列
1 | template<typename T> |
Actor 基类
1 | class Actor : public std::enable_shared_from_this<Actor> { |
Ping-Pong 演示
两个 Actor 互相发消息,演示消息传递而非共享变量:
1 | class PingActor : public Actor { |
demo 还包含:Counter Actor、Worker Pool、状态机 Actor。
六、协程 vs Actor vs 线程池
| 模型 | 优势 | 劣势 | 适用 |
|---|---|---|---|
| 线程池 | 成熟、简单 | 回调地狱、共享状态 | CPU 密集、通用并发 |
| 协程 | 异步代码线性化 | 生态仍在发展 | I/O 密集、网络服务 |
| Actor | 无共享状态、易推理 | 消息开销、调试难 | 分布式、状态机、游戏 |
1 | 选型决策树: |
三者可组合:Actor 内部用协程处理消息,线程池作为协程调度器。
七、运行 demo
1 | cd ref/cpp_demo/projects/learning_guide |
协程演示:Generator 基础、斐波那契、map/filter/take 组合、Task 异步、调度器。
Actor 演示:Mailbox 多线程、Ping-Pong、Counter、Worker Pool、状态机。
需要 C++20 编译器(协程支持)。
八、系列总结:28 篇回顾
「现代 C++ 实战」系列至此完结。28 篇(00–27)覆盖五条主线:
| 季 | 篇号 | 主题 | 核心收获 |
|---|---|---|---|
| 第零季 | 00–02 | 环境与基础 | CMake、版本地图、工具链 |
| 第一季 | 03–11 | 语言特性 | 移动语义、智能指针、Lambda、C++17/20/23 |
| 第二季 | 12–17 | 并发与工程 | 线程、同步、线程池、设计模式、测试 |
| 第三季 | 18–23 | 算法与数据结构 | 排序、哈希、树、图、字符串、DP |
| 第四季 | 24–27 | 进阶项目 | HTTP、SQLite、LRU/JSON、协程/Actor |
1 | 学习路线建议: |
39 个 demo 在 ref/cpp_demo/,统一 ./build.sh --run 运行。大纲详见 docs/CPP_SERIES_OUTLINE.md。
九、小结
| 要点 | 内容 |
|---|---|
| 协程 | co_yield / co_await / co_return |
| Generator | 惰性序列,支持 map/filter/take |
| Task | 异步任务 + 调度器 |
| Actor | 消息传递、Mailbox、无共享状态 |
| 选型 | I/O→协程,隔离→Actor,CPU→线程池 |
现代 C++ 实战系列 27 篇(含第 00 篇)全部完结。 感谢阅读,Happy Coding!










