协程是 C++20 引入的一项强大特性,它让异步编程变得像同步编程一样直观。下面我们通过一个简单的网络请求示例,演示如何使用协程实现异步 IO,并讨论常见的陷阱与最佳实践。
1. 协程基础
协程通过 co_yield、co_return、co_await 等关键字实现“暂停”和“恢复”功能。协程函数的返回类型必须是 std::experimental::generator、**`std::experimental::generator
`** 或 **`std::experimental::task`**(后者在标准 C++20 中是 `std::future` 的一个包装)。
“`cpp
#include
#include
#include
#include
std::future async_http_get(const std::string& url);
“`
### 2. 异步 HTTP GET 的协程实现
下面的示例演示如何用协程包装 `std::async`,并在等待期间让线程池或事件循环继续执行其它任务。
“`cpp
#include
#include
#include
#include
#include
#include
// 模拟网络请求的耗时操作
std::string fake_http_get(const std::string& url)
{
std::this_thread::sleep_for(std::chrono::seconds(2));
return “Response from ” + url;
}
// 把耗时操作包装成协程
std::future async_http_get(const std::string& url)
{
// 这里用 std::async 来模拟异步操作,真实项目可替换成 ASIO 等库
return std::async(std::launch::async, fake_http_get, url);
}
// 协程入口
std::future
process_requests(const std::vector& urls)
{
for (const auto& url : urls)
{
// 发起异步请求
std::future fut = async_http_get(url);
// 这里可以做其他工作,例如更新 UI
std::cout **注意**:C++20 标准库并没有直接提供 `co_await` 的实现,`std::future` 本身不支持协程。实际使用时应依赖 **`std::experimental::task
`** 或第三方库(如 `cppcoro`、`libcoro`、`asio` 的协程适配器)。上例为伪代码,展示思路。
### 3. 事件循环与协程
在实际项目中,协程往往与事件循环(Event Loop)配合使用。下面是一个简化的事件循环示例,展示如何将协程与 `select`/`epoll` 等 IO 复用机制整合。
“`cpp
#include
#include
#include
class EventLoop {
public:
EventLoop() { epfd_ = epoll_create1(0); }
~EventLoop() { close(epfd_); }
void add_fd(int fd, int events)
{
epoll_event ev{};
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev);
}
void run()
{
while (true) {
std::array events;
int nfds = epoll_wait(epfd_, events.data(), events.size(), -1);
for (int i = 0; i