c++异网高效发送数据

原文
strand,锁+发送队列和提交+发送队列,哪种方法更好呢?性能说话.答案是提交+发送队列>锁+发送队列>strand.
提交方法连续发送数据的另一个好处是,内部io线程需要连续发送数据时是无锁的,只有提交那里有锁,锁的范围很小,同时也影响io线程发数据的效率,它的效率无疑是最高的.
另一个场景,需要发送一段数据到服务端,数据包括包头和包体,包头中有表示包体长度的长度字段,服务端先读包头解析出包体长度后再读包体.客户端这样发送数据的:

空 发送(串 负载){
    向量<符>缓冲;
    大小型 大小=负载.大小();
    缓冲.调整(大小+4);

    复制内存(缓冲.数据(),&大小,4);//包头
    复制内存(缓冲.数据()+4,负载.数据(),大小);
//包体.

    异步写(异网::缓冲(缓冲));//发送.
}

代码很简单,先构造完整长度的缓冲,然后拷贝包头,再拷贝包体,最后发送.这里有个问题就是有一内存分配(一次是负载,一次是缓冲)和两次内存拷贝,性能较低.如何优化性能呢?可用零拷贝来发送数据.

0拷贝

代码变成:

空 发送(串 负载){
    向量<异网::常缓冲>缓冲;

    大小型 大小=负载.大小();符 头[4];
    复制内存(头,&大小,4);
    缓冲.压后(异网::缓冲(头,4));
    缓冲.压后(异网::缓冲(负载.数据(),负载.大小()));
    异步写(缓冲);
}

这里代码没有分配内存,只有一次memcpy(head),效率比之前高很多,这里省掉了复制负载,称为零拷贝方式发送数据,或者称为分散-聚集方式,asio提供了发送std::vectorasio::常缓冲的接口,使用它可实现零拷贝方式发送数据.
零拷贝底层用writev来一次发送多个缓冲.

虽然零拷贝避免了额外分配和拷贝内存,但是一次发送多个缓冲的效率并没有一次发送大缓冲效率高,所以要看具体情况,如果是小数据,分配和拷贝内存代价较小反而比零拷贝方式更高效.

再改进

避免多次分配内存和发送多个缓冲:

空 发送(串 负载){
    向量<异网::常缓冲>缓冲;

    大小型 偏移=4,大小=负载.大小()-偏移;
    复制内存(负载.数据(),&大小,4);
    异步写(异网::缓冲(负载.数据(),负载.大小()));
}

这里在构造负载时候预留出包头部分长度,保证后面发送时不会再复制负载,只复制包头很少的数据,同时一次发送负载,效率更高.

posted @   zjh6  阅读(20)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示