协程(coroutine)在C++20中正式加入标准库,提供了对轻量级协作式并发的原生支持。相比传统的线程,协程具有更低的创建与切换成本,更直观的代码结构以及更好的可组合性。本文将从协程的基本概念、语法实现、典型使用场景以及未来发展趋势四个方面,系统阐述C++协程的技术细节和实践价值。
1. 协程的基本概念
协程是一种在多任务之间共享执行上下文的程序结构。它允许在运行时暂停(yield)或恢复(resume)函数的执行,而不需要将执行权完全交给调度器。协程的核心是 暂停点(suspend point)和 恢复点(resume point)。在C++20中,协程通过 co_await、co_yield、co_return 三个关键字实现协作式暂停与返回。
co_await:在等待一个 awaitable 对象时暂停协程。
co_yield:生成一个值并暂停协程,等待下一个调用。
co_return:终止协程并返回一个值。
协程的状态由 promise 对象管理,promise 保存协程的结果、异常信息以及对外部接口的访问。协程函数的返回类型是 std::future、std::generator 或自定义 `generator
`。
## 2. 协程的语法实现
下面给出一个最简的协程实现例子:计算斐波那契数列。
“`cpp
#include
#include
#include
template
struct Generator {
struct promise_type {
T current_value;
std::optional
value_;
std::exception_ptr exception_;
Generator get_return_object() {
return Generator{std::coroutine_handle
::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 = value;
value_ = value;
return {};
}
void return_void() {}
void unhandled_exception() { exception_ = std::current_exception(); }
};
std::coroutine_handle
coro;
explicit Generator(std::coroutine_handle
h) : coro(h) {}
~Generator() { if (coro) coro.destroy(); }
bool next() {
coro.resume();
return !coro.done();
}
T value() const { return coro.promise().current_value; }
};
Generator
fibonacci(int n) {
int a = 0, b = 1;
for (int i = 0; i < n; ++i) {
co_yield a;
int next = a + b;
a = b;
b = next;
}
}
int main() {
auto gen = fibonacci(10);
while (gen.next()) {
std::cout << gen.value() << " ";
}
std::cout << std::endl;
}
“`
该例子展示了:
1. **promise_type**:定义了协程的生命周期、暂停与恢复逻辑。
2. **Generator**:包装协程句柄,提供 `next()` 与 `value()` 接口。
3. **协程函数 fibonacci**:使用 `co_yield` 生成值。
编译时需使用支持 C++20 的编译器,例如 `-std=c++20`。运行结果为:`0 1 1 2 3 5 8 13 21 34`。
## 3. 典型使用场景
### 3.1 异步 I/O
协程非常适合处理异步 I/O,尤其在网络编程中可以让代码保持同步式的写法。典型的库有 `Boost.Asio` 的协程支持、`cppcoro`、`libcoro` 等。
“`cpp
#include
#include
asio::awaitable
async_echo(asio::ip::tcp::socket sock) {
char buffer[1024];
std::size_t n = co_await sock.async_read_some(asio::buffer(buffer), asio::use_awaitable);
co_await asio::async_write(sock, asio::buffer(buffer, n), asio::use_awaitable);
co_return;
}
“`
### 3.2 并行流水线
在 CPU 密集型或数据流处理时,可用协程实现流水线结构。每个阶段是一个协程,数据通过 `co_yield` 传递,避免显式的线程间通信。
### 3.3 生成器与迭代器
协程天然地实现了生成器模式,适用于需要按需生成大量数据的场景,例如大规模日志解析、图像处理等。
## 4. 与线程的对比
| 维度 | 线程 | 协程 |
|——|——|——|
| 创建成本 | 1-2 ms | < 1 μs |
| 切换成本 | ~10 μs | ~1 μs |
| 并发模型 | preemptive | cooperative |
| 调度控制 | OS 负责 | 程序控制 |
协程的轻量级特性使得在单核或多核场景下都能更好地利用资源。需要注意的是,协程仍然是同步执行的,真正的并行需要配合多线程或多进程。
## 5. 未来发展趋势
### 5.1 标准化扩展
C++23 已经扩展了协程的基础设施,例如 `std::generator`、`std::ranges::generator`、`std::as_writable` 等。未来的标准可能进一步简化错误处理、异常传播以及协程间的通信。
### 5.2 与并行/分布式计算结合
协程与 SIMD、GPU、异构计算平台的结合正在探索中。通过协程的暂停点与多核调度,可以实现更高效的任务切片与数据并行。
### 5.3 生态完善
伴随协程的普及,社区将陆续出现更成熟的库,例如 `cppcoro`、`co_await` 的第三方实现以及跨平台的异步框架。学习并使用这些工具,可以让开发者在 C++ 项目中快速实现高性能异步编程。
## 6. 小结
C++协程在标准化后提供了强大的异步编程能力。通过 `co_await`、`co_yield` 与 `co_return`,开发者可以编写更为清晰、可维护且高效的代码。未来随着标准进一步演进和生态完善,协程将成为构建高性能并发系统的首选工具。希望本文能为你开启协程世界的探索之旅。