https://github.com/netcan/asyncio 这个项目解决了什么问题?有什么原创性?
这是个很值得深挖的项目。综合来看,它的原创性比名字暗示的更有实质性。
它解决了什么问题
C++20 在语言层面加入了协程(coroutines),但只给了你原始机制:co_await、co_yield、co_return 这些关键字,以及 promise_type、coroutine_handle 这些底层接口。标准委员会故意不提供运行时——没有事件循环、没有任务调度器、没有 I/O 原语、没有同步工具。
这意味着任何想用 C++20 协程做异步编程的人,都必须自己实现整套运行时基础设施。而正确实现这些东西极其复杂:协程帧的生命周期管理、挂起点的所有权语义、取消传播的正确性……每一项都是足以踩坑数周的领域。
netcan/asyncio 做的就是把这套运行时基础设施做出来,并且选择了一个具体的 API 设计目标:让 C++ 的异步代码看起来和 Python asyncio 一模一样。
// Python: results = await asyncio.gather(task_a(), task_b(), task_c()) // netcan/asyncio C++: auto [a, b, c] = co_await asyncio::gather(task_a(), task_b(), task_c());
这不只是改个名字,gather() 返回的是编译期确定类型的 tuple,用 C++17 结构化绑定直接解包,类型安全,零开销。
有哪些原创性
1. 用 await_transform + std::source_location 实现异步调用栈还原(最独特的技术点)
协程最让开发者头疼的调试问题是:传统调用栈在 co_await 处断裂,因为协程帧在堆上,挂起后栈帧已经不存在了。调试器只能看到当前帧,完全不知道”是谁发起了这个 await”。
netcan/asyncio 的解法是:在 promise_type 里重载 await_transform()——C++ 协程规定每一次 co_await 都会先经过这个函数——在这里用 std::source_location::current() 记录当前 await 发生的文件、行号、函数名,形成一条链。这样就可以在运行时 dump 出完整的异步调用链:
asyncio callstack: #0 tcp_echo_client at example/echo_client.cpp:12 #1 main at example/echo_client.cpp:20
这个技术在 2021 年项目创建时,在 C++ 开源社区里极少有人实现,是作者对 C++20 协程机制深度理解后的原创工程技巧。
2. 结构化并发的 C++ 实现
gather()、wait_for()、取消传播这套 API 对应的是 Python asyncio 的结构化并发模型——一组任务要么全部完成,要么一个取消带动其他全部取消。在 C++ 里实现这个的难点是:取消信号要穿透协程帧传递,且取消时要正确析构所有挂起状态。项目通过异常机制实现取消传播,设计是干净的。
3. 纯 C++20,无外部异步运行时依赖
不依赖 libuv、不依赖 Boost.Asio 的事件循环,完全从 C++20 标准库的协程机制和 epoll/io_uring 构建,保持了极小的层次数。这在同类项目里不常见——大多数 C++ 协程库要么垫在 ASIO 之上,要么垫在 libuv 之上。
性能表现
基准测试(10M 请求、1000 并发、echo server):
| 框架 | RPS |
|---|---|
| netcan/asyncio | 164,457 |
| libuv | 159,937 |
| ASIO 1.18 | 159,322 |
| Tokio (Rust) | 156,852 |
| Python asyncio+uvloop | 100,426 |
| Python asyncio | 47,393 |
领先 ASIO 约 3%,领先 Tokio 约 5%——差距在同等量级内,说明C++20 原生协程的切换开销约 10 纳秒,与 IO 本身的毫秒级延迟相比几乎可忽略,不是瓶颈。
客观评价
真正有价值的地方:
await_transform+source_location的调试技巧是真实的技术创新,后来已被其他项目借鉴- Python asyncio API 的 C++ 映射是一个清晰且自洽的设计哲学,降低了认知门槛
- 代码本身是学习 C++20 协程机制的极佳参考,结构清晰,没有过度抽象
局限:
- 定位是教学/研究级项目,不是生产级库——错误处理、跨平台兼容性、压力测试覆盖都不完整
- 与已归档的 cppcoro(Lewis Baker 的协程库,标准委员会委员级别的作品)相比,功能完备性差距较大
- 单线程事件循环模型对多核利用没有设计
与前作 zhanglix/asyncio 的本质区别: zhanglix 的版本用的是 2017 年 LLVM 的实验性协程 TS,是早期探索;netcan 的版本是完整 C++20 标准特性,是生产语言的正式特性实现——两者虽然名字相似,技术路径完全不同。
总结:这是一个技术深度扎实、有清晰设计哲学、带有一两个真正原创技巧的高质量个人项目。在 C++20 协程生态还很荒芜的 2021-2022 年,它是少数把”可用的异步运行时”这件事认真做出来的 C++ 开源作品之一。
Sources:
