• c++异网高效发送数据


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

    空 发送(串 负载){
        向量<>缓冲;
        大小型 大小=负载.大小();
        缓冲.调整(大小+4);
    
        复制内存(缓冲.数据(),&大小,4);//包头
        复制内存(缓冲.数据()+4,负载.数据(),大小);
    //包体.
    
        异步写(异网::缓冲(缓冲));//发送.
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    0拷贝

    代码变成:

    空 发送(串 负载){
        向量<异网::常缓冲>缓冲;
    
        大小型 大小=负载.大小();符 头[4];
        复制内存(,&大小,4);
        缓冲.压后(异网::缓冲(,4));
        缓冲.压后(异网::缓冲(负载.数据(),负载.大小()));
        异步写(缓冲);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

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

    再改进

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

    空 发送(串 负载){
        向量<异网::常缓冲>缓冲;
    
        大小型 偏移=4,大小=负载.大小()-偏移;
        复制内存(负载.数据(),&大小,4);
        异步写(异网::缓冲(负载.数据(),负载.大小()));
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

  • 相关阅读:
    动态 SQL
    Elasticsearch分布式模式下读写流程
    Pytest之用例执行--并发执行、重复执行、输出报告
    android HAL 执行权限写法
    【从0到1开发一个网关】网关Mock功能的实现
    如何理解go语言中的“为类型定义一个方法“?
    基于ssm的图书(借阅)管理系统
    2022-9-20-C++11新特性
    Android 9 MTK 更改系统的版本号
    8个常见的机器学习算法的计算复杂度总结
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/126460383