如何在 C++20 中实现协程(coroutine)并利用它们来简化异步 IO?

C++20 引入了协程(coroutine)这一强大特性,使得异步编程可以以同步代码的风格书写,从而大幅降低复杂度。下面通过一个完整的例子,演示如何使用协程实现一个简易的异步 IO 框架,并展示如何利用它来简化网络请求的编写。

1. 协程基本概念

  • co_await:挂起协程,等待一个异步操作完成后恢复执行。
  • co_return:结束协程并返回一个值。
  • co_yield:产生一个值给调用者,常用于生成器。
  • std::coroutine_handle:协程句柄,用于控制协程生命周期。

协程本质上是一个状态机,编译器会把协程函数拆解为生成器和状态机代码,隐藏细节。

2. 简单的异步任务包装器

我们先实现一个 `Task

` 类型,它代表一个异步操作,最终会返回类型 `T`。该类型需要实现 `await_ready`、`await_suspend` 和 `await_resume` 三个成员函数。 “`cpp #include #include #include #include #include #include #include template struct Task { struct promise_type { std::optional result_; std::exception_ptr eptr_; Task get_return_object() { return Task{std::coroutine_handle ::from_promise(*this)}; } std::suspend_never initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(T value) { result_ = std::move(value); } void unhandled_exception() { eptr_ = std::current_exception(); } // For co_yield T&& yield_value(T value) { result_ = std::move(value); return std::move(value); } }; std::coroutine_handle coro_; explicit Task(std::coroutine_handle h) : coro_(h) {} Task(const Task&) = delete; Task(Task&& other) noexcept : coro_(other.coro_) { other.coro_ = nullptr; } ~Task() { if (coro_) coro_.destroy(); } bool await_ready() noexcept { return false; } void await_suspend(std::coroutine_handle awaiting) noexcept { // 简单模拟异步:在后台线程执行 std::thread([this, awaiting]() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); coro_.resume(); // 触发协程继续执行 }).detach(); } T await_resume() { if (coro_.promise().eptr_) std::rethrow_exception(coro_.promise().eptr_); return std::move(coro_.promise().result_.value()); } }; “` ### 3. 模拟网络请求 下面用 `Task` 表示一个异步网络请求,返回响应内容。 “`cpp Task fetch_url(const std::string& url) { std::cout main_coroutine() { std::string data1 = co_await fetch_url(“https://example.com/api/1”); std::cout ` 通过 `await_suspend` 在后台线程完成模拟异步 | ### 7. 小结 – C++20 的协程让异步代码以同步写法表达,极大提升可读性与维护性。 – 通过自定义 `Task `,我们能轻松封装任何异步操作(I/O、数据库、网络等)。 – 与传统基于回调的异步编程相比,协程避免了回调地狱,使错误处理和资源管理更直观。 在实际项目中,可将上述框架与 `asio`、`libuv` 等异步库结合,实现高性能的异步服务器或客户端。祝你玩得开心,写出更简洁、高效的 C++ 异步代码!

发表评论