C++20 Coroutine: 让异步编程更简单

在 C++20 中,协程(Coroutine)被正式纳入标准库,提供了比传统回调、状态机或 Future 更直观的异步编程模型。协程的核心概念是“挂起”与“恢复”,它允许函数在执行期间暂停,等待某个事件完成后再继续执行,从而实现非阻塞 I/O、流式数据处理以及复杂的业务逻辑。以下从实现原理、使用场景、性能优势以及常见陷阱四个方面,深入剖析协程在 C++20 中的价值与实践技巧。

1. 协程的基本原理

协程本质上是一种能够在不同点挂起和恢复的函数。它在编译时被转换为一个状态机,内部保存必要的局部变量、返回点与挂起点的状态。编译器会把 co_awaitco_yieldco_return 等关键字转化为对状态机的操作,从而实现暂停与继续。

  • co_await:挂起当前协程,等待等待对象(如异步 I/O)完成后再恢复执行。
  • co_yield:返回一个值给调用者,并挂起协程,等待下一次 next() 调用。
  • co_return:结束协程,返回最终结果。

协程函数的返回类型不再是 voidT,而是 `std::generator

`(用于 `co_yield`)或 `std::future` / `std::task`(用于 `co_await`)。C++20 通过 `std::experimental::coroutine_handle` 提供低级接口,允许自定义协程框架。 ## 2. 常见使用场景 | 场景 | 传统实现 | 协程实现 | |——|———-|———-| | 异步文件读写 | 回调链 / Future | `co_await async_read(file)` | | 网络 I/O | Reactor / Proactor | `co_await async_recv(sock)` | | 数据流处理 | 手动状态机 | `co_yield` 生成器 | | 并行计算 | 线程池 + 条件变量 | `co_await` 并行任务 | ### 示例:异步 HTTP 客户端 “`cpp #include #include #include #include #include struct awaitable_socket { int sock; awaitable_socket(int s) : sock(s) {} bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle h) { // 这里可以注册 epoll 或者 IOCP,完成后再 resumption // 简化起见,直接 sleep std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::string await_resume() const noexcept { char buf[1024]; ssize_t n = read(sock, buf, sizeof(buf)); return std::string(buf, n); } }; struct task { struct promise_type { task get_return_object() { return {}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; }; task async_http_get(const std::string& host, const std::string& path) { int sock = socket(AF_INET, SOCK_STREAM, 0); // … 连接 host std::string request = “GET ” + path + ” HTTP/1.1\r\nHost: ” + host + “\r\n\r\n”; send(sock, request.c_str(), request.size(), 0); std::string response = co_await awaitable_socket(sock); std::cout

发表评论