**标题:在 C++20 中使用协程实现异步文件读取**

在现代 C++(从 C++20 开始)中,协程(coroutine)为我们提供了一种简洁、高效的异步编程模型。本文将从零开始,演示如何使用协程实现一个异步文件读取函数,并通过一个简单的主程序进行调用。我们将涉及以下内容:

  1. 何谓协程以及它在 C++20 中的实现方式
  2. 通过 std::experimental::generator 实现协程生成器
  3. 使用 std::asyncstd::future 与协程结合的技巧
  4. 完整代码示例与详细注释
  5. 如何在实际项目中使用此模式

1. 协程概念回顾

C++20 引入了 co_awaitco_yieldco_return 关键字,让函数可以在执行过程中挂起并恢复。协程函数返回一个 协程类型,通常是 std::futurestd::generator 或自定义类型。协程的主要优势:

  • 轻量:挂起点不需要线程上下文切换,CPU 只需记录当前状态。
  • 易读:代码保持同步写法,逻辑顺序清晰。
  • 高效:适合 IO 密集型任务,避免了频繁的线程阻塞。

2. 生成器 std::experimental::generator

在 C++20 的实验性库中,`std::experimental::generator

` 允许我们在函数内部使用 `co_yield` 产生一个可迭代的序列。它非常适合读取文件时按行返回数据。下面给出一个读取文件行的协程: “`cpp #include #include #include #include #include #include using namespace std::experimental; // 读取文本文件每一行,使用协程生成器返回 generator async_read_lines(const std::string& path) { std::ifstream file(path); if (!file) { co_return; // 文件无法打开,直接结束协程 } std::string line; while (std::getline(file, line)) { // 每读到一行,挂起协程,将行内容交给调用者 co_yield line; } } “` ### 如何使用 “`cpp int main() { for (auto&& line : async_read_lines(“sample.txt”)) { std::cout #include #include #include #include #include using namespace std::experimental; // 生成器返回 vector ,在后台完成后返回给 future std::future> async_file_reader(const std::string& path) { return std::async(std::launch::async, [path]() { std::vector lines; std::ifstream file(path); if (!file) { return lines; // 空向量表示文件打开失败 } std::string line; while (std::getline(file, line)) { lines.push_back(line); } return lines; }); } int main() { auto future = async_file_reader(“sample.txt”); // 这里可以做其他工作 std::cout `,支持 `co_return` 语句: “`cpp #include #include #include template struct task { struct promise_type { T value_; std::exception_ptr eptr_; auto get_return_object() { return task{std::coroutine_handle ::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() { eptr_ = std::current_exception(); } void return_value(T val) { value_ = std::move(val); } }; std::coroutine_handle coro_; task(std::coroutine_handle h) : coro_(h) {} ~task() { if (coro_) coro_.destroy(); } T get() { if (coro_.promise().eptr_) std::rethrow_exception(coro_.promise().eptr_); return std::move(coro_.promise().value_); } }; “` 使用示例: “`cpp task async_add(int a, int b) { co_return a + b; } int main() { auto t = async_add(5, 7); std::cout

发表评论