**标题:C++20 协程与异步编程的实战指南**

在 C++20 之前,想要实现异步或协程式编程,通常需要依赖第三方库如 Boost.Coroutine、libuv 或自己实现状态机。C++20 标准把协程的语法和语义正式纳入语言,提供了 co_awaitco_yieldco_return 关键字和 std::coroutine_handle 等工具,使得异步编程更接近同步写法。下面从概念、实现细节以及一个完整示例四个层面展开。


1. 协程基本概念

关键字 作用 典型使用场景
co_await 暂停协程,等待一个可等待对象完成 异步 I/O、网络请求
co_yield 暂停协程,返回一个值给调用者 生成器、流式数据
co_return 结束协程并返回结果 异步函数结束时返回值

协程本质上是一个轻量级的函数状态机。与普通函数不同,协程在每次暂停时保存完整的调用上下文(局部变量、栈帧、指令指针等),下次恢复时从暂停点继续执行。


2. 关键标准库组件

组件 简介 典型实现
`std::experimental::generator
| C++20 之前的实验性生成器实现 |`
`std::coroutine_handle
| 关联协程句柄 |std::coroutine_handle`
std::suspend_always / std::suspend_never 默认挂起策略 `
`
`std::future
/std::shared_future| 与协程组合的异步结果容器 |`
std::thread + std::async 传统异步调用 `
`

C++20 通过 `

` 头文件统一了协程相关的基底类型。协程的返回类型必须具备 **promise_type**,并提供 `initial_suspend()`、`final_suspend()`、`get_return_object()`、`return_value()` 等成员函数。 — ## 3. 实现细节 ### 3.1 promise_type “`cpp template struct AsyncPromise { std::promise p_; AsyncPromise() = default; AsyncPromise(const AsyncPromise&) = delete; auto get_return_object() { return AsyncFuture{std::coroutine_handle ::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(T value) { p_.set_value(std::move(value)); } void unhandled_exception() { p_.set_exception(std::current_exception()); } }; “` ### 3.2 AsyncFuture “`cpp template class AsyncFuture { public: explicit AsyncFuture(std::coroutine_handle<asyncpromise> h) : handle_(h), fut_(h.promise().p_.get_future()) {} std::future get() { return std::move(fut_); } private: std::coroutine_handle<asyncpromise> handle_; std::future fut_; }; “` ### 3.3 一个异步读取文件的示例 “`cpp #include #include #include #include #include #include template struct AsyncPromise; template class AsyncFuture; template struct AsyncPromise { std::promise p_; AsyncFuture get_return_object() { return AsyncFuture {std::coroutine_handle::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(T value) { p_.set_value(std::move(value)); } void unhandled_exception() { p_.set_exception(std::current_exception()); } }; template class AsyncFuture { public: explicit AsyncFuture(std::coroutine_handle<asyncpromise> h) : h_(h), fut_(h.promise().p_.get_future()) {} std::future get() { return std::move(fut_); } private: std::coroutine_handle<asyncpromise> h_; std::future fut_; }; AsyncFuture async_read_file(const std::string& path) { std::ifstream file(path, std::ios::binary); if (!file) { throw std::runtime_error(“File not found”); } std::string content((std::istreambuf_iterator (file)), std::istreambuf_iterator ()); co_return content; } int main() { auto fut = async_read_file(“sample.txt”); std::cout << "Reading file asynchronously…\n"; // 在主线程里做点别的 std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "File content length: " << fut.get().get().size() << '\n'; } “` — ## 4. 优势与局限 | 优势 | 局限 | |——|——| | 语义接近同步写法,减少回调地狱 | 协程内部栈分配可能不确定,需谨慎 | | 与 `std::future` 直接配合,易于错误处理 | 标准库对协程的工具仍在完善,第三方库更成熟 | | 支持生成器、异步 I/O、协程池等多种模式 | 需要编译器完全支持 C++20,旧版本不兼容 | — ## 5. 未来趋势 – **协程池**:将协程调度交给池化线程,减少线程切换成本。 – **与 I/O 完全无阻塞**:结合 `asio` 等异步 I/O 库,提供完全事件驱动的网络层。 – **更丰富的协程包装**:如 `cppcoro::task`、`tl::expected` 等第三方实现,提供更友好的 API。 — ### 结语 C++20 协程为语言带来了强大的异步能力,彻底改变了传统的回调和事件循环模型。掌握协程的核心概念、实现细节以及实际应用场景,是每个现代 C++ 开发者不可或缺的技能。希望本文能帮助你快速上手,开启协程式编程之旅。</asyncpromise</asyncpromise</asyncpromise</asyncpromise

发表评论