**C++20中的三种协程实现方式**

协程是C++20引入的重要特性,它允许程序在执行过程中暂停并在之后恢复,极大地方便了异步编程、生成器以及状态机的实现。C++20提供了三种主要的协程实现方式:标准协程(co_await/co_yield/co_return)、基于Boost.Coroutine的协程以及使用第三方库(如cppcoro、asio)的协程。下面分别介绍这三种方式的特点、使用场景以及优缺点。


1. 标准协程(co_await/co_yield/co_return

1.1 基本语法

#include <coroutine>
#include <iostream>

struct Generator {
    struct promise_type {
        int current_value;
        std::suspend_always yield_value(int v) {
            current_value = v;
            return {};
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        Generator get_return_object() { return {}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };
    std::coroutine_handle <promise_type> handle;
};

Generator range(int start, int end) {
    for (int i = start; i <= end; ++i)
        co_yield i;
}

1.2 典型用途

  • 异步 I/O:配合std::future或自定义awaiter实现异步网络请求、文件读取。
  • 生成器:如上面例子所示,用co_yield生成序列。
  • 状态机:通过co_await暂停状态,并在外部触发恢复。

1.3 优点与缺点

优点 缺点
与标准库完全集成,语法简洁 需要C++20编译器支持
内存开销可控,堆栈大小可配置 对初学者学习曲线较陡峭
可以与其他异步框架无缝对接 调试时堆栈信息不直观

2. Boost.Coroutine(协程库)

2.1 基本使用

#include <boost/coroutine2/all.hpp>
#include <iostream>

void foo(boost::coroutines2::coroutine <int>::push_type& yield) {
    for (int i = 0; i < 5; ++i)
        yield(i);
}

int main() {
    boost::coroutines2::coroutine <int>::pull_type source(foo);
    while (source)
        std::cout << source.get() << " ";
    return 0;
}

2.2 适用场景

  • 兼容性需求:在不支持C++20的项目中使用协程。
  • 可定制堆栈:可以自定义堆栈大小、堆栈分配器。
  • 与Boost库生态:与boost::asioboost::beast等无缝集成。

2.3 优点与缺点

优点 缺点
兼容旧编译器(C++11/14/17) API 较为低级,使用不够直观
细粒度控制协程行为 需要手动管理协程生命周期
与Boost其他组件深度集成 与标准协程不完全兼容,代码迁移成本高

3. 第三方协程库(cppcoro、asio、gsl)

3.1 cppcoro

cppcoro是一个轻量级的协程工具库,提供了诸如generator, task, pipeline等抽象。

#include <cppcoro/generator.hpp>
#include <iostream>

cppcoro::generator <int> range(int start, int end) {
    for (int i = start; i <= end; ++i)
        co_yield i;
}

int main() {
    for (auto v : range(1, 5))
        std::cout << v << " ";
}

3.2 asio(Boost.Asio的协程支持)

Boost.Asio自C++20起支持co_await,也可以使用asio::awaitable

#include <boost/asio.hpp>
#include <iostream>

boost::asio::awaitable <void> async_print() {
    std::cout << "Start\n";
    co_await boost::asio::this_coro::executor;
    std::cout << "End\n";
}

3.3 GSL(Guidelines Support Library)协程实验

Microsoft Research的GSL项目提供了一套协程实验性接口,尚处于实验阶段。

3.4 适用场景与优点

  • 异步网络编程:asio + coroutine能实现高性能I/O。
  • 简化生成器:cppcoro的generator使用方式与标准协程相似。
  • 实验性特性:GSL为实验性协程提供了可测试的实现。

3.5 缺点

  • 第三方依赖会增加构建复杂度。
  • 与标准协程的兼容性不一,迁移时需注意。
  • 一些库仍在维护阶段,更新不及时。

4. 如何选择合适的协程实现?

需求 推荐实现
纯粹使用标准C++20功能 标准协程
需要在旧编译器或C++17项目中使用 Boost.Coroutine
需要高级异步网络或文件I/O asio + 协程
想快速原型化生成器、状态机 cppcoro

5. 小结

C++20的协程特性为现代C++程序员提供了强大且灵活的异步编程模型。标准协程以其简洁的语法和与标准库的无缝对接成为首选;Boost.Coroutine为需要向后兼容的项目提供了解决方案;而第三方库如cppcoro和asio则在特定领域提供了成熟的实现。根据项目需求、编译器版本以及依赖管理,选择最合适的协程实现将帮助你更高效地构建可维护且性能优秀的 C++ 软件。

发表评论