文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

2308C++简单异步改造网络库

2023-09-09 18:18

关注

简单异步可以轻松改造同步网络库从而获得大幅性能提升,用它改造异步回调网络库可以让我们以同步方式写代码,让代码更简洁,可读性更好,还能避免回调地狱的问题.
本文通过两个例子分别来介绍如何用简单异步改造基于asio的同步网络库和异步回调网络库.

示例依赖了独立版的asio(commitid:f70f65ae54351c209c3a24704624144bfe8e70a3),它是headeronly的直接包含头文件即可.

以一个同步的echo server/client为例,先来看看echoserver:

空 开始服务器(异网::io环境&io环境,正 短 端口){    传控::受者 a(io环境,传控::端点(传控::v4(),端口));(;;){[错误,套接字]=接受(a);        会话(::移动(套接字));    }}

echoserver启动时先监听端口,然后同步accept,当有新连接到来时在会话中处理网络读写事件.

<型名 异网缓冲>::<异网::错误码,大小型>读些(异网::ip::传控::套接字&套接字, 异网缓冲&&缓冲){    异网::错误码 错误;    大小型 长度=套接字.读些(::前向<异网缓冲>(缓冲),错误);    中 标::造双(错误,长度);}空 会话(传控::套接字 套接字){(;;){        常 大小型 最大长度=1024;        符 数据[最大长度];[错误,长度]=读些(套接字,数据,最大长度);(套接字,数据,长度);    }}

循环中先同步读数据,再把读到的数据发送到对端.

同步的echo client:

空 开始(异网::io环境&io环境,::串 主机,::串 端口){[ec,套接字]=连接(io环境,主机,端口);    常 整 最大长度=1024;    符 写缓冲[最大长度]={"你好 简单异步"};    符 读缓冲[最大长度];    常 整 数=10000;(整 i=0;i<;++i){(套接字,写缓冲,最大长度);[错误,回复长度]=读些(套接字,读缓冲,最大长度);        //处理数据.    }}

同步的echoclient也是类似的过程,先连接,再循环发送数据和读数据.整个逻辑都是同步的,代码简单易懂.

当然,因为整个过程都是同步等待的,所以无法并发的处理网IO事件,性能是比较差的.如果用简单异步来改造这个同步的网络库则可以大幅提升网络库的性能(参考benchmark),而且需要修改的代码很少,这就是简单异步的威力.

简单异步::协程::<>会话(传控::套接字 套接字){(;;){        常 大小型 最大长度=1024;        符 数据[最大长度];[错误,长度]=            协待 异步读些(套接字,异网::缓冲(数据,最大长度));        协待 异步写(套接字,异网::缓冲(数据,长度));    }::错误码 ec;    套接字.关闭(异网::ip::传控::套接字::都关闭,ec);    套接字.关闭(ec);::输出<<"完成回声消息,总:"<<消息索引-1<<".\n";}简单异步::协程::<>开始服务器(异网::io环境&io环境, 正 短 端口, 简单异步::执行器*E){    传控::受者 a(io环境,传控::端点(传控::v4(),端口));(;;){[错误,套接字]=协待 异步接受(a);        会话(::移动(套接字)).通过(E).开始([](&&){});    }}

可以看到用简单异步改造的start_server会话相比,返回类型变成了Lazy,同步接口变成了co_await async_xxx,原有的同步逻辑没有任何变化,这个微小的改动即可让我们把同步网络库改成异步协程网络库从而让性能得到巨大的提升.

更多的代码细节请看demo_exampleechoserver/client的例子.

对于一些已有的异步回调网络库,也可以用简单异步来消除回调,从而让我们可以用同步方式去使用异步接口,让代码变得更简洁易懂.

asio异步httpserver为例:

空 连接::干读(){  动 本(从本共享());  套接字_.异步读些(异网::缓冲(缓冲_),      [,](::错误码 ec,::大小型 传输字节)      {(!ec)        {          请求解析器::结果类型 结果;::绑定(结果,::忽略)=请求解析器_.解析(请求_,缓冲_.数据(),缓冲_.数据()+传输字节);(结果==请求解析器::)          {            请求处理器_.请求处理(请求_,回复_);            干写();          }          异 如(结果==请求解析器::)          {            回复_=回复::回复股票(回复::坏请求);            干写();          }{            干读();          }        }        异 如(ec!=异网::错误::中止操作)        {          连接管_.停止(从本共享());        }      });}空 连接::干写(){  动 本(从本共享());  异网::异步写(套接字_,回复_.到缓冲(),      [,](::错误码 ec,::大小型)      {(!ec)        {          异网::错误码 忽略误码;          套接字_.关闭(异网::ip::传控::套接字::都关闭, 忽略误码);        }(ec!=异网::错误::中止操作)        {          连接管_.停止(从本共享());        }      });}

可以看到基于回调的异步网络库的代码,比同步网络库复杂很多,如在异步读的回调中如果没有读到完整数据需要递归调用do_read,如果读到完整数据之后才能在回调中调用异步写接口.同时,还要注意将shared_from_this()得到的std::shared_ptr传入到异步接口的回调函数中以保证安全的回调.总之,异步回调代码的编写难度较大,可读性也较差,如果用简单异步改造则可以较好的解决这些问题,性能也不会降低.

简单异步::协程::<>干读(){    动 本(从本共享());(;;){[错误,传输字节]=            协待 异步读些(套接字_,异网::缓冲(读缓冲_));(错误){;}        请求解析器::结果类型 结果;::绑定(结果,::忽略)=解析器_.解析(            请求_,读缓冲_,读缓冲_+传输字节);(结果==请求解析器::){            请求处理(请求_,响应_);            协待 异步写(套接字_,响应_.到缓冲());        }异 如(结果==请求解析器::){            响应_=构建响应(状态类型::坏请求);            协待 异步写(套接字_,响应_.到缓冲());;        }    }}

简单异步改造之后的httpserver完全消除了回调函数,完全可按同步方式写异步代码,简洁易懂.
测试结果,提高2倍速度!

来源地址:https://blog.csdn.net/fqbqrr/article/details/132225921

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯