使用C++20协程实现异步文件读取的完整示例

在C++20中,协程(Coroutines)为异步编程提供了原生语法支持。下面给出一个完整示例,演示如何使用std::experimental::generator(在C++20的实验特性中)读取文件内容,并利用协程实现非阻塞的异步文件读取。

核心思路

  1. 异步读取任务:定义一个返回std::future的函数,内部使用协程读取文件。
  2. 协程生成器:利用std::experimental::generator<std::string>逐行产生文件内容。
  3. 主线程:启动异步任务,随后继续执行其他业务逻辑,最终等待结果。

代码示例

#include <iostream>
#include <fstream>
#include <string>
#include <future>
#include <experimental/coroutine>

// 1. 生成器类型,逐行返回文件内容
template<typename T>
using generator = std::experimental::generator <T>;

// 2. 协程生成器实现
generator<std::string> read_file_lines(const std::string& path) {
    std::ifstream fin(path);
    if (!fin) {
        co_yield "ERROR: Cannot open file.";
        co_return;
    }

    std::string line;
    while (std::getline(fin, line)) {
        co_yield line;          // 生成下一行
    }
}

// 3. 异步读取函数,返回 std::future<std::vector<std::string>>
std::future<std::vector<std::string>> async_read_file(const std::string& path) {
    return std::async(std::launch::async, [path] {
        std::vector<std::string> result;
        for (auto&& line : read_file_lines(path)) {
            if (line.rfind("ERROR", 0) == 0) { // 错误行
                result.push_back(line);
                break;
            }
            result.push_back(line);
        }
        return result;
    });
}

// 4. 主程序演示
int main() {
    const std::string file_path = "sample.txt";

    // 启动异步读取
    std::future<std::vector<std::string>> future = async_read_file(file_path);

    // 主线程可以做其他事情
    std::cout << "正在进行其他工作...\n";
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "其他工作完成。\n";

    // 等待读取结果
    std::vector<std::string> lines = future.get();

    std::cout << "读取到的文件内容:\n";
    for (const auto& l : lines) {
        std::cout << l << '\n';
    }

    return 0;
}

实现细节说明

  • read_file_lines 使用 co_yield 逐行产生文件内容,若文件无法打开则直接返回错误信息。
  • async_read_file 调用 std::async 以后台线程启动协程,返回 std::future,可以在主线程中非阻塞地等待结果。
  • 主线程在等待文件读取完成期间可执行其他任务,真正体现了异步协程的优势。

编译指令

g++ -std=c++20 -pthread -lstdc++experimental -o async_read async_read.cpp

注意:-lstdc++experimental 用于链接实验性协程支持库,若使用 Clang,请相应改为 -stdlib=libc++

扩展思路

  1. 错误处理:在协程内部使用异常或 std::optional 进一步细化错误信息。
  2. 大文件优化:改用缓冲读取(如 std::ifstream::read),避免一次性将整个文件读入内存。
  3. 跨平台异步:结合 asioboost::asio,实现真正意义上的非阻塞 I/O。

通过以上示例,你可以看到 C++20 的协程不仅语法优雅,而且能轻松实现高并发、异步的文件 I/O。希望对你后续的异步编程实践有所帮助。

发表评论