C++ 协程:从 asyncio 理解现代异步编程
背景 现代编程离不开异步。Python 有 asyncio,JavaScript 有 async/await,Go 有 goroutine。C++20 终于引入了协程(Coroutines)。 今天从 Python asyncio 的视角来看看 C++ 协程怎么用。 Python asyncio 的模式 async def fetch(url: str) -> str: # 模拟异步IO await asyncio.sleep(1) return f"data from {url}" async def main(): results = await asyncio.gather( fetch("a.com"), fetch("b.com"), fetch("c.com"), ) print(results) asyncio.run(main()) 核心概念:async def 定义协程函数,await 挂起等待,asyncio.gather 并发执行。 C++20 协程入门 C++ 协程的关键类型: co_await — 挂起协程 co_return — 返回值(相当于 return) co_yield — 产出值(用于生成器) std::suspend_never / std::suspend_always — 挂起策略 简单例子:模拟异步任务 #include <coroutine> #include <future> #include <iostream> template<typename T> struct Task { struct promise_type { T value; std::exception_ptr error; auto get_return_object() { return Task{std::coroutine_handle<promise_type>::from_promise(*this)}; } auto initial_suspend() { return std::suspend_never{}; } auto final_suspend() noexcept { return std::suspend_always{}; } void return_value(T v) { value = v; } void unhandled_exception() { error = std::current_exception(); } }; std::coroutine_handle<promise_type> handle; Task(std::coroutine_handle<promise_type> h) : handle(h) {} ~Task() { if (handle) handle.destroy(); } T get() { handle.resume(); return handle.promise().value; } }; // 模拟异步操作 Task<int> async_fetch() { std::cout << "开始异步任务...\n"; co_await std::suspend_always{}; // 挂起,模拟异步等待 std::cout << "异步任务完成\n"; co_return 42; } int main() { auto task = async_fetch(); std::cout << "做一些其他事情...\n"; int result = task.get(); std::cout << "结果: " << result << "\n"; } 和 Python asyncio 对比 Python C++ async def Task<T> 返回类型 await co_await return value co_return value asyncio.sleep(1) std::suspend_always{} 事件循环自动调度 手动 resume() 实际应用:HTTP 客户端 Task<Response> http_get(const std::string& url) { co_await socket_.async_connect(url); co_await socket_.async_write(request_); Response resp = co_await socket_.async_read(); co_return resp; } Task<std::vector<Response>> fetch_all(const std::vector<std::string>& urls) { std::vector<Task<Response>> tasks; for (const auto& url : urls) { tasks.push_back(http_get(url)); } std::vector<Response> results; for (auto& task : tasks) { results.push_back(task.get()); } co_return results; } 坑点 协程不能用在模板参数里 — std::vector<Task<int>> 可以,但 Task<Task<int>> 不行 生命周期管理 — 协程句柄必须手动 destroy(),除非用 RAII 封装 调试困难 — 栈帧被编译器切分,gdb 支持还在完善中 总结 C++20 协程还很年轻,库支持不如 Python 完善。但对于构建高性能网络服务,它的零成本抽象是其他语言难以比拟的。 ...