C++20 协程:协程基础与实战案例

在 C++20 中,协程(Coroutine)被正式引入标准库,提供了一种新的异步编程模型,既可以写出像同步代码一样直观的逻辑,又能高效地管理资源。本文从协程的基本概念入手,逐步演示如何使用 std::generatorstd::task,并给出一个完整的网络请求与文件写入的实战案例,帮助读者快速上手。

一、协程概述

协程是一种可挂起的函数,调用时并不会立即执行完毕,而是可以在执行过程中“挂起”,等待某些条件满足后再恢复。C++20 通过关键字 co_await, co_yield, co_return 实现协程的挂起、产生值和返回结果。

  • co_await:等待一个可等待对象(Awaitable),暂停协程直到其完成。
  • co_yield:产生一个值,暂停协程直到下一个 co_yield 或协程结束。
  • co_return:结束协程并返回值。

二、核心类型

2.1 std::generator

`std::generator ` 是一个可迭代的协程,适合需要按需产生一系列值的场景。其实现方式类似于 `std::vector`,但内存消耗更低,因为只在需要时生成值。 “`cpp std::generator range(int start, int end) { for (int i = start; i `std::task ` 用于表示异步操作,类似于 `std::future`,但不阻塞线程。它支持 `co_await` 等待操作完成,并可以链式调用。 “`cpp std::task async_read(const std::string& path) { std::ifstream ifs(path); std::string content((std::istreambuf_iterator (ifs)), std::istreambuf_iterator ()); co_return content; } “` ## 三、实战案例:异步 HTTP GET 与文件写入 下面给出一个完整的示例,演示如何使用协程实现一个异步 HTTP GET 请求,然后将结果写入磁盘。为简化实现,使用 `asio`(Boost.Asio)作为网络库,并在 C++20 标准协程基础上封装 `asio::awaitable`。 ### 3.1 环境准备 “`bash # 安装 Boost 和 ASIO(单头文件版本可直接使用) sudo apt-get install libboost-dev libboost-system-dev libboost-thread-dev “` ### 3.2 代码实现 “`cpp #include #include #include #include #include #include #include using asio::awaitable; using asio::ip::tcp; using asio::use_awaitable; using namespace std::chrono_literals; // 异步 HTTP GET 请求 awaitable http_get(const std::string& host, const std::string& path) { auto executor = co_await asio::this_coro::executor; tcp::resolver resolver(executor); auto endpoints = co_await resolver.async_resolve(host, “http”, use_awaitable); tcp::socket socket(executor); co_await asio::async_connect(socket, endpoints, use_awaitable); // 构造请求 std::string request = “GET ” + path + ” HTTP/1.1\r\n”; request += “Host: ” + host + “\r\n”; request += “Connection: close\r\n\r\n”; co_await asio::async_write(socket, asio::buffer(request), use_awaitable); // 读取响应 std::string response; asio::streambuf buffer; while (true) { std::size_t n = co_await asio::async_read(socket, buffer, asio::transfer_at_least(1), use_awaitable); if (n == 0) break; std::istream is(&buffer); std::string line; std::getline(is, line); response += line + “\n”; } co_return response; } // 异步文件写入 awaitable async_write_file(const std::string& path, const std::string& data) { auto executor = co_await asio::this_coro::executor; asio::steady_timer timer(executor, std::chrono::seconds(1)); // 模拟异步写入 co_await timer.async_wait(use_awaitable); std::ofstream ofs(path, std::ios::binary); ofs.write(data.c_str(), data.size()); ofs.close(); } // 主协程 awaitable main_coro() { try { std::string host = “example.com”; std::string path = “/”; std::cout

发表评论