## 题目:C++20 中协程的基础与实战

C++20 为语言引入了协程(coroutines),为异步编程提供了更优雅的语法。相比传统的 std::futurestd::async 或第三方库(如 Boost.Asio、libuv),协程可以让代码保持同步风格,减少回调地狱。下面先从语法入手,然后给出一个完整的实战案例——异步文件读取。

1. 协程概念回顾

协程是一种可挂起和恢复的函数。C++ 通过关键字 co_awaitco_yieldco_return 实现:

  • co_return:结束协程并返回值。
  • co_yield:在迭代器风格的协程中返回一个值,挂起执行。
  • co_await:挂起协程直到等待对象完成。

C++ 标准提供了两大核心类型:`std::generator

`(C++23)和 `std::task`(C++23),但 C++20 需要自定义 `promise_type` 以实现自定义协程。 ### 2. 基础示例:生成器 下面是一个最小可运行的协程生成器,生成前 N 个整数: “`cpp #include #include template struct generator { struct promise_type { T current_value; std::suspend_always yield_value(T value) { current_value = value; return {}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } generator get_return_object() { return generator{std::coroutine_handle ::from_promise(*this)}; } void unhandled_exception() { std::terminate(); } void return_void() {} }; std::coroutine_handle coro; explicit generator(std::coroutine_handle h) : coro(h) {} ~generator() { if (coro) coro.destroy(); } T next() { coro.resume(); return coro.promise().current_value; } }; generator count(int n) { for (int i = 0; i #include #include #include #include #include template struct async_task { struct promise_type { T value; std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } async_task get_return_object() { return async_task{std::coroutine_handle ::from_promise(*this)}; } void unhandled_exception() { std::terminate(); } void return_value(T v) { value = std::move(v); } }; std::coroutine_handle coro; explicit async_task(std::coroutine_handle h) : coro(h) {} ~async_task() { if (coro) coro.destroy(); } T get() { coro.resume(); return std::move(coro.promise().value); } }; async_task read_file_async(const std::string& path) { // 模拟异步 I/O,实际环境可使用平台异步 API co_return []() -> std::string { std::ifstream fin(path, std::ios::binary); if (!fin) return “文件打开失败”; std::string data((std::istreambuf_iterator (fin)), std::istreambuf_iterator()); return data; }(); } “` #### 3.2 主程序 “`cpp int main() { auto task = read_file_async(“sample.txt”); std::string content = task.get(); std::cout 说明:这里的 `read_file_async` 实际上仍在同步线程读取文件,但它返回的是一个协程。若将 I/O 调度放到专门的线程池或异步 I/O API(如 POSIX `aio_*` 或 Windows `ReadFileEx`)中,协程的挂起/恢复将真正做到非阻塞。 ### 4. 优势与局限 **优势** – 代码更接近同步写法,易读易维护。 – 协程的挂起点可以是任何 `awaitable`,实现灵活。 – 与异步线程池、事件循环天然兼容。 **局限** – 标准库尚未提供完整的异步 I/O 支持,需结合平台或第三方。 – 协程编译成本较传统函数更高。 – 对调试工具的支持仍在完善中。 ### 5. 小结 C++20 的协程为异步编程打开了新的思路。通过自定义 `promise_type`,可以轻松实现生成器、任务等模式。将协程与事件循环、线程池相结合,即可构建高性能、易维护的异步应用。随着 C++23 的到来,协程相关类型(如 `std::generator`、`std::task`)将进一步简化使用,值得期待。

发表评论