C++20 Coroutines
C++20 协程是语言级别的异步编程支持,通过
co_await/co_yield/co_return让异步代码像同步代码一样书写。
核心概念
协程三要素:
co_await — 挂起当前协程,等待异步操作完成
co_yield — 挂起并产出一个值(生成器)
co_return — 协程返回值并结束
协程机制:
Promise — 控制协程的行为(如何挂起、如何返回值)
Awaitable — 可以被 co_await 的对象
Coroutine Handle — 协程的句柄,用于恢复执行生成器(Generator)
cpp
#include <coroutine>
#include <optional>
// 简单生成器实现
template<typename T>
class Generator {
public:
struct promise_type {
T current_value;
Generator get_return_object() {
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T value) {
current_value = std::move(value);
return {};
}
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
using handle_type = std::coroutine_handle<promise_type>;
explicit Generator(handle_type h) : handle_(h) {}
~Generator() { if (handle_) handle_.destroy(); }
Generator(Generator&& other) noexcept : handle_(other.handle_) {
other.handle_ = nullptr;
}
// 迭代器支持
struct iterator {
handle_type handle;
bool operator!=(std::default_sentinel_t) const { return !handle.done(); }
iterator& operator++() { handle.resume(); return *this; }
T& operator*() { return handle.promise().current_value; }
};
iterator begin() { handle_.resume(); return {handle_}; }
std::default_sentinel_t end() { return {}; }
private:
handle_type handle_;
};
// 使用生成器
Generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a;
auto next = a + b;
a = b;
b = next;
}
}
Generator<int> range(int start, int end, int step = 1) {
for (int i = start; i < end; i += step) {
co_yield i;
}
}
// 使用
for (int n : range(0, 10, 2)) {
std::cout << n << " "; // 0 2 4 6 8
}
auto fib = fibonacci();
int count = 0;
for (int n : fib) {
if (count++ >= 10) break;
std::cout << n << " "; // 0 1 1 2 3 5 8 13 21 34
}异步任务(Task)
cpp
#include <coroutine>
// 简单 Task 实现(类似 C# Task / Rust Future)
template<typename T = void>
class Task {
public:
struct promise_type {
std::optional<T> result;
std::exception_ptr exception;
std::coroutine_handle<> continuation; // 等待此 Task 的协程
Task get_return_object() {
return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
struct FinalAwaiter {
bool await_ready() noexcept { return false; }
void await_resume() noexcept {}
std::coroutine_handle<> await_suspend(
std::coroutine_handle<promise_type> h) noexcept {
if (h.promise().continuation)
return h.promise().continuation;
return std::noop_coroutine();
}
};
FinalAwaiter final_suspend() noexcept { return {}; }
void return_value(T value) { result = std::move(value); }
void unhandled_exception() { exception = std::current_exception(); }
};
using handle_type = std::coroutine_handle<promise_type>;
// Awaitable 接口
bool await_ready() { return handle_.done(); }
void await_suspend(std::coroutine_handle<> h) {
handle_.promise().continuation = h;
}
T await_resume() {
if (handle_.promise().exception)
std::rethrow_exception(handle_.promise().exception);
return std::move(*handle_.promise().result);
}
explicit Task(handle_type h) : handle_(h) {}
~Task() { if (handle_) handle_.destroy(); }
private:
handle_type handle_;
};
// 使用 Task
Task<int> fetch_data(int id) {
// 模拟异步操作
co_return id * 42;
}
Task<std::string> process() {
int data = co_await fetch_data(10); // 等待异步结果
co_return "result: " + std::to_string(data);
}实用库:cppcoro / libcoro
cpp
// 实际项目中使用成熟的协程库
// cppcoro:https://github.com/lewissbaker/cppcoro
// libcoro:https://github.com/jbaldwin/libcoro
#include <cppcoro/task.hpp>
#include <cppcoro/sync_wait.hpp>
#include <cppcoro/when_all.hpp>
cppcoro::task<int> compute(int x) {
co_return x * x;
}
cppcoro::task<void> main_task() {
// 顺序执行
int r1 = co_await compute(3);
int r2 = co_await compute(4);
// 并发执行
auto [a, b] = co_await cppcoro::when_all(compute(5), compute(6));
std::cout << r1 << " " << r2 << " " << a << " " << b << "\n";
}
int main() {
cppcoro::sync_wait(main_task());
}Boost.Asio 协程
cpp
#include <boost/asio.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/use_awaitable.hpp>
namespace asio = boost::asio;
using tcp = asio::ip::tcp;
// 协程风格的异步 HTTP 请求
asio::awaitable<std::string> fetch(std::string host, std::string path) {
auto executor = co_await asio::this_coro::executor;
tcp::resolver resolver(executor);
// 异步 DNS 解析(看起来像同步!)
auto endpoints = co_await resolver.async_resolve(host, "80",
asio::use_awaitable);
tcp::socket socket(executor);
co_await asio::async_connect(socket, endpoints, asio::use_awaitable);
std::string request = "GET " + path + " HTTP/1.0\r\nHost: " + host + "\r\n\r\n";
co_await asio::async_write(socket, asio::buffer(request), asio::use_awaitable);
std::string response;
co_await asio::async_read_until(socket, asio::dynamic_buffer(response),
"\r\n\r\n", asio::use_awaitable);
co_return response;
}
int main() {
asio::io_context io;
asio::co_spawn(io, fetch("example.com", "/"), [](auto eptr, std::string result) {
if (eptr) std::rethrow_exception(eptr);
std::cout << result << "\n";
});
io.run();
}关键认知
C++20 协程是无栈协程(stackless),挂起时只保存局部状态,内存开销极小。标准库只提供底层机制,实际使用需要配合 Boost.Asio、cppcoro 等库。协程让异步代码的可读性接近同步代码,是高性能 I/O 的未来方向。