在现代C++中,协程(coroutine)为异步编程提供了自然且高效的方式。本文将演示如何利用C++20标准库中的std::generator、std::task以及std::future,配合异步 I/O 库(如 asio 或自定义)实现一个简易的异步文件读取示例。整个过程分为三大部分:定义协程类型、实现异步读取逻辑以及调度与使用。
1. 环境与依赖
- C++20(支持协程的编译器,如 GCC 10+、Clang 12+、MSVC 16.9+)
- ASIO(Boost.Asio 或 standalone ASIO) 负责异步 I/O
- `#include
`, `#include `, `#include `
2. 协程返回类型:`Task
`
“`cpp
template
struct Task {
struct promise_type {
std::promise
promise_;
Task get_return_object() { return Task{promise_.get_future()}; }
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_value(T value) noexcept { promise_.set_value(std::move(value)); }
void unhandled_exception() { promise_.set_exception(std::current_exception()); }
};
std::future
fut_;
explicit Task(std::future
fut) : fut_(std::move(fut)) {}
std::future
& operator()() { return fut_; }
};
“`
### 3. 异步读取文件的协程函数
“`cpp
Task async_read_file(const std::string& path) {
using namespace asio::ip;
asio::io_context ctx;
asio::posix::stream_descriptor file(ctx, ::open(path.c_str(), O_RDONLY));
std::vector
buffer(4096);
std::string result;
while (true) {
std::size_t n = co_await asio::async_read(file, asio::buffer(buffer),
asio::use_future);
if (n == 0) break; // EOF
result.append(buffer.data(), n);
}
co_return result;
}
“`
> 说明
> – `asio::async_read` 返回一个 `std::future`,协程通过 `co_await` 取得读字节数。
> – 当文件读取完毕(返回0)时退出循环,最终将完整内容通过 `co_return` 返回。
### 4. 调度与调用
“`cpp
int main() {
auto task = async_read_file(“example.txt”);
std::future fut = task(); // 获取 future
std::string content = fut.get(); // 阻塞等待读取完成
std::cout << "文件内容长度: " << content.size() << "\n";
}
“`
### 5. 关键点回顾
1. **协程的 Promise**
– `promise_type` 内部持有 `std::promise
`,将最终结果通过 `return_value` 设置给 `future`。
– `initial_suspend` 与 `final_suspend` 采用 `suspend_never`,让协程立即开始执行,结束后直接完成。
2. **异步 I/O 与协程配合**
– ASIO 的 `async_read` 与 `use_future` 组合,让 `co_await` 直接等待 `future`。
– 读取循环可以灵活处理任意大小文件,不必一次性读入。
3. **可扩展性**
– 通过替换 `async_read` 的实现,可轻松改为网络流、数据库查询等异步任务。
– `Task
` 的设计可以进一步增强错误处理、取消支持等。
### 6. 进一步思考
– **取消机制**:在协程内部捕获 `asio::error::operation_aborted`,并通过 `promise_` 设置异常。
– **并发读取**:使用 `asio::strand` 或 `asio::async_compose` 统一调度。
– **性能调优**:将缓冲区大小设为 8KB、16KB 或使用 `mmap` 加速大文件读取。
通过以上示例,你可以快速上手 C++20 协程与异步 I/O 的结合,构建高性能、易维护的异步文件读取框架。祝编码愉快!