原文
strand
,锁+发送
队列和提交+发送
队列,哪种方法更好呢?性能说话.答案是提交+发送队列>锁+发送队列>strand
.
提交
方法连续发送数据
的另一个好处是,内部io
线程需要连续发送数据
时是无锁的,只有提交
那里有锁,锁的范围很小,同时也影响io
线程发数据的效率
,它的效率无疑是最高的
.
另一个场景,需要发送一段数据
到服务端,数据包括包头和包体
,包头
中有表示包体
长度的长度
字段,服务端
先读包头
解析出包体长度
后再读包体
.客户端这样发送数据
的:
空 发送(串 负载){
向量<符>缓冲;
大小型 大小=负载.大小();
缓冲.调整(大小+4);
复制内存(缓冲.数据(),&大小,4);//包头
复制内存(缓冲.数据()+4,负载.数据(),大小);
//包体.
异步写(异网::缓冲(缓冲));//发送.
}
代码很简单,先构造完整长度的缓冲
,然后拷贝包头
,再拷贝包体
,最后发送
.这里有个问题
就是有一内存分配
(一次是负载
,一次是缓冲
)和两次内存拷贝
,性能较低
.如何优化性能呢?可用零拷贝
来发送数据.
代码变成:
空 发送(串 负载){
向量<异网::常缓冲>缓冲;
大小型 大小=负载.大小();符 头[4];
复制内存(头,&大小,4);
缓冲.压后(异网::缓冲(头,4));
缓冲.压后(异网::缓冲(负载.数据(),负载.大小()));
异步写(缓冲);
}
这里代码没有分配内存
,只有一次memcpy(head)
,效率比之前高很多,这里省掉了复制负载
,称为零拷贝
方式发送数据,或者称为分散-聚集
方式,asio
提供了发送std::vectorasio::常缓冲
的接口,使用
它可实现零拷贝
方式发送数据
.
零拷贝
底层用writev
来一次发送多个缓冲
.
虽然零拷贝
避免了额外分配和拷贝
内存,但是一次发送多个缓冲
的效率并没有一次发送大缓冲
效率高,所以要看具体
情况,如果是小数据
,分配和拷贝
内存代价较小反而比零拷贝
方式更高效.
避免多次分配
内存和发送多个
缓冲:
空 发送(串 负载){
向量<异网::常缓冲>缓冲;
大小型 偏移=4,大小=负载.大小()-偏移;
复制内存(负载.数据(),&大小,4);
异步写(异网::缓冲(负载.数据(),负载.大小()));
}
这里在构造负载
时候预留出包头
部分长度,保证后面发送
时不会再复制负载
,只复制
包头很少的数据,同时一次发送负载
,效率更高.