使用 C++ 20 协程降低异步网络编程复杂度
传统异步回调 vs C++20协程
基于回调的异步网络编程
async_resolve({host, port}, [](auto endpoint){
async_connect(endpoint, [](auto error_code){
async_handle_shake([](auto error_code){
send_data_ = build_request();
async_write(send_data_, [](auto error_code){
async_read();
});
});
});
});
void async_read() {
async_read(response_, [](auto error_code){
if(!finished()) {
append_response(recieve_data_);
async_read();
}else {
std::cout<<"finished ok\n";
}
});
}
- 异步域名解析
- 异步连接
- 异步 SSL 握手
- 异步发送数据
- 异步接收数
基于协程的异步网络编程
auto endpoint = co_await async_query({host, port});
auto error_code = co_await async_connect(endpoint);
error_code = co_await async_handle_shake();
send_data = build_request();
error_code = co_await async_write(send_data);
while(true) {
co_await async_read(response);
if(finished()) {
std::cout<<"finished ok\n";
break;
}
append_response(recieve_data_);
}
C++ 20 协程提案之争
- 无栈指可挂起/恢复的函数
- 有栈协程则相当于用户态线程
栈空间的限制
性能
无栈协程是普通函数的泛化

无栈协程原理
void fn(){
int a, b, c;
a = b + c;
yield();
b = c + a;
yield();
c = a + b;
}
Struct fn{
int a, b, c;
int __state = 0;
void resume(){
switch(__state) {
case 0:
return fn1();
case 1:
return fn2();
case 2:
return fn3();
}
}
void fn1(){
a = b + c;
}
void fn2(){
b = c + a;
}
void fn3(){
c = a + b;
}
};
上面就将一个协程函数 fn 进行切分后变成一个Struct,这样的实现相对于有栈协程而言使用的内存更少。当然上面只是一种演示,对应早期的 reenter 用法,这个宏底层通过 switch-case 将函数拆分成多个可重入点,一般也称为 duff device。
C++20 协程缺点
- 协程帧 (coroutine frame)
- 协程参数
- 局部变量
- promise 对象
- promise_type
- coroutine return object
- std::coroutine_handle
- co_await、awaiter、awaitable




协程库
- boost::asio
- coroutine / reenter / yield / fork
- spawn / strand / yield_context
- (C++20) io_context / executor / co_spawn / co_await / co_return / use_awaitable / executor
- boost::coroutine2 [有栈协程]
- coroutine<>::pull_type / coroutine<>::push_type / coro_back / sink
- boost::fiber [coroutine2 + 协程调度器 + 协程同步工具]
- fiber / buffered_channel<> / barrier / mutex / channel / promise / future / condition_variable / sleep / yield
- cppcoro [C++20]
- async_simple [阿里]
- libco [腾讯,有栈协程]
- libcopp [有栈协程]
接入
- -std=c++2a
- -fcoroutines-ts
- -DASIO_STA_ALONE
- gcc 10
- msvc
- 1900 (VS2015 14.0 部分支持)
- 1910 (VS2017 15.0 ts 支持)
- 1928 (VS2019 16.8)
- clang 8 (部分支持)
- 概念 (concept)
- 范围 (ranges)
- 协程 (coroutine)
- 模块 (modules)
实例
#include <asio/co_spawn.hpp>
#include <asio/detached.hpp>
#include <asio/io_context.hpp>
#include <asio/ip/tcp.hpp>
#include <asio/signal_set.hpp>
#include <asio/write.hpp>
#include <cstdio>
#include <iostream>
using asio::ip::tcp;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;
namespace this_coro = asio::this_coro;
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# define use_awaitable \
asio::use_awaitable_t(__FILE__, __LINE__, __PRETTY_FUNCTION__)
#endif
awaitable<void> echo(tcp::socket socket)
{
try
{
char data[1024];
for (;;)
{
std::size_t n = co_await socket.async_read_some(asio::buffer(data), use_awaitable);
co_await async_write(socket, asio::buffer(data, n), use_awaitable);
}
}
catch (std::exception& e)
{
std::printf("echo Exception: %s\n", e.what());
}
}
void fn2(){
std::cout<<"hhh\n";
}
void fn(){
fn2();
}
awaitable<void> listener()
{
auto executor = co_await this_coro::executor;
fn();
tcp::acceptor acceptor(executor, {tcp::v4(), 8988});
for (;;)
{
tcp::socket socket = co_await acceptor.async_accept(use_awaitable); //调用协程,体现同步性
co_spawn(executor, echo(std::move(socket)), detached);// 创建连接处理线程
}
}
int main()
{
try
{
asio::io_context io_context(1);
asio::signal_set signals(io_context, SIGINT, SIGTERM);
signals.async_wait([&](auto, auto){ io_context.stop(); });
co_spawn(io_context, listener(), detached); // 创建纤程,体现并发性
io_context.run(); // 开始调度
}
catch (std::exception& e)
{
std::printf("Exception: %s\n", e.what());
}
}
参考
[1]. 在 Boost.Asio 中使用协程
[2]. C++20协程原理和应用
[3]. C++网络编程之asio(五)——在asio中使用协程
[4]. C++20协程不完全指南
[5]. 深入浅出c++协程
[7]. 聊聊协程的发展历程
[8]. asio服务器模式:协程
[10]. Boost中的协程—Boost.Asio中的coroutine类
[11]. 如何在C++17中实现stackless coroutine以及相关的任务调度器
[12]. C++20 Coroutine实例教学
[13]. 译:你的第一个协程程序(Your first coroutine)
[14]. ASIO 与协程
[15]. C++ compiler support
使用 C++ 20 协程降低异步网络编程复杂度的更多相关文章
- 第十一章:Python高级编程-协程和异步IO
第十一章:Python高级编程-协程和异步IO Python3高级核心技术97讲 笔记 目录 第十一章:Python高级编程-协程和异步IO 11.1 并发.并行.同步.异步.阻塞.非阻塞 11.2 ...
- C++20协程实例:携程化的IOCP服务端/客户端
VC支持协程已经有一段时间了,之前一直想不明白协程的意义在哪里,前几天拉屎的时候突然灵光一闪: 以下是伪代码: task server() { for (;;) { sock_context s = ...
- 带你简单了解python协程和异步
带你简单了解python的协程和异步 前言 对于学习异步的出发点,是写爬虫.从简单爬虫到学会了使用多线程爬虫之后,在翻看别人的博客文章时偶尔会看到异步这一说法.而对于异步的了解实在困扰了我好久好久,看 ...
- Python实现基于协程的异步爬虫
一.课程介绍 1. 课程来源 本课程核心部分来自<500 lines or less>项目,作者是来自 MongoDB 的工程师 A. Jesse Jiryu Davis 与 Python ...
- python协程与异步协程
在前面几个博客中我们一一对应解决了消费者消费的速度跟不上生产者,浪费我们大量的时间去等待的问题,在这里,针对业务逻辑比较耗时间的问题,我们还有除了多进程之外更优的解决方式,那就是协程和异步协程.在引入 ...
- 进击的Python【第十章】:Python的高级应用(多进程,进程间通信,协程与异步,牛逼的IO多路复用)
Python的socket高级应用(多进程,协程与异步) 一.多进程multiprocessing multiprocessing is a package that supports spawnin ...
- 进击的Python【第十章】:Python的socket高级应用(多进程,协程与异步)
Python的socket高级应用(多进程,协程与异步)
- day-5 python协程与I/O编程深入浅出
基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1. 什么是协程(以下内容来自维基百 ...
- Python-09-线程、进程、协程、异步IO
0. 什么是线程(thread)? 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆 ...
- python 自动化之路 day 10 协程、异步IO、队列、缓存
本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 RabbitMQ队列 Redis\Memcached缓存 Paramiko SSH Twsited网络框架 引子 到目 ...
随机推荐
- CPrimerPlus
还没学 的 167页的wordcnt程序 199页的checking程序(太长了,不想看) 113页的第八章编程练习5(不想看) 125页的复习题9(有问题,有时间再来验证) 119页重定向和文件(n ...
- pandas 如何移动列的位置
实现效果 原来备注列在第二列 代码: mid=df['备注'] #取备注列的值 df.pop('备注') #删除备注列 df.insert(4,'备注',mid) #插入备注列
- 【Loongson】支持AXI总线接口
概述 支持axi接口.但其实没有burst,没有cache,没有tlb,所以仿真起来全是空泡,冲突转发相关功能正确性就测不出来. 从sram改为axi:等待时间从一拍到看信号握手 主要更改/bug处: ...
- 如何编写Kubernetes的YAML(一)
什么是API对象 作为一个集群操作系统,Kubernetes 归纳总结了 Google 多年的经验,在理论层面抽象出了很多个概念,用来描述系统的管理运维工作,这些概念就叫做"API 对象&q ...
- B@se-还原错误字母表转码的base64编码
题目: 密文:MyLkTaP3FaA7KOWjTmKkVjWjVzKjdeNvTnAjoH9iZOIvTeHbvD== JASGBWcQPRXEFLbCDIlmnHUVKTYZdMovwipatNOe ...
- Unsloth更快训练大模型并导出GGUF - Windows
环境搭建 系统环境 需要Nvidia显卡,至少8G显存,且专用显存与共享显存之和大于20G 建议将非安装版的环境文件都放到非系统盘,方便重装或移植 以Windows11为例,非安装环境文件都放在 E ...
- nacos(八): sentinel——基本使用
一.概要 在微服务的架构中,流控是一个重要的任务.sentinel是阿里开源的流量治理组件,针对访问的"资源"或服务路径进行流控,内置了限流.熔断及系统负载保护等功能. senti ...
- D的SDK的设置
有点烦,被困扰.看大虾的文章一并感谢: 进入D:\Users\Public\Documents\Embarcadero\Studio\22.0\CatalogRepository\AndroidSDK ...
- 2025年Anaconda官网最新版本Anaconda下创建虚拟环境,并在新创建的虚拟环境下一次性安装多个软件包的经验总结
一.为了使用tensorflow软件包中的tensorboard软件包工具,在python==3.12.8环境下创建虚拟环境pytorch,使用命令行如下.1.1 使用Anaconda prompt, ...
- Lua 的os.date()
Lua os.date() os.date## 原型:os.date ([format [, time]]) 解释:返回一个按format格式化日期.时间的字串或表. usage## 参数格式: 由原 ...