最初, 这种设计, 是考虑: 网卡再快, 也不可能会比一个CPU快吧, 然后设计这个单线程收发.
但却被告之: 多线程进行收发效率才会更快. recvfrom可能单线程多线程没什么影响, 但sendto多线程却效果非常明显...想明白原因..为何多线程调用sendto会比单线程全速调用sendto要效率高那么多呢? 明明都是互锁资源...
12 个解决方案
#1
多线程调用sendto相当于多个回应同时进行,效率肯定比单线程高的。
#2
什么多个回应? 一块网卡, sendto操作同一个socket, 按道理当两个线程进入的时候就会互锁, 只有等一个线程完成操作后才轮到第二个线程处理吧? 这个sendto操作貌似也没有什么IO等待的, 起码单线程死循环的时候, 看到一个CPU核会被占用100%.
#3
你对线程的理解完全错位了。并不是说一旦线程运行就必须完全执行完成这个线程CPU才去做其它的事情,每个线程的运行都是由CPU的时间片决定的,有可能线程执行了一半的时候CPU去做其它事情了,windows核心编程第8章有详细介绍,建议楼主去看一看。
#4
CPU操作网卡是通过总线来操作的,除非你收发2个网卡,不然没用,而且收发使用不同的网卡要自己改TCP/IP协议栈底层(IP层以下的)的代码,一般不要那样做,一般提高网络连接的程序是通过修改IP层代码,主要是方法是预先通知应用层做出动作,减少传输层与IP层的逻辑连路冲突等方法来解决的,像你那样搞也可以但代价不是一般高,而且改协议栈过于底层的东西移植,测试,维护都成问题
#5
在线程和CPU核数上面, 可以确保一个线程对应有一个CPU核直接使用的, 而且线程均是无锁的形式, 所以不存在你说的问题的.
而且我想知道的问题, 还是为何sendto被多线程调用会比单线程调用效率要高
#6
按你的说法来说, 你也是认同没有必要多个线程操作同一个socket来sendto是吧? 但实际上却是多个线程调用sendto效率几倍
#7
LZ看来你还不太理解多线程,哪个只是个调度方案,而不必然提高效率,线程本身就占一定的资源开多了占资源,开多了频繁的上下文切换影响系统效率,而你想搞网络优化首先知道些硬件跟OS地层的东西,现在网卡能支持到TCP/IP到什么程度,目前网卡按硬件支持TCP/IP协议栈的程度划分主要分为:1 MAC层网卡(只取得物理连路数据,并对数据做NZ,FM0等编解码的,这个一些ARM处理器自带用CAN总线的EMAC模块差不多),2.IP层网卡(网卡能支持到TCP/IP的IP层,ICMP那些协议网卡已经做了硬件上的支持,PC端的协议栈就不用做IP层以下的工作,而交给网卡做),3.全协议网卡(至少支持到传输层的,PC只需给网卡发数据就行,怎么发网卡搞完), 而网卡跟CPU通讯要么通过总线要么通过间接连接(CPU跟内存的连接方式),读上去的数据要么通过DMA中断要么经过某个FIFO将数据交给操作系统(操作系统驱动做的),一般WINDOWS会虚拟个设备地址映射这些数据,也就是说无论你开多少线程最后都是将数据串行后放到那区域,不然的话发送数据出错甚至蓝屏,所以哪个意义不大,网络数据的吞吐量并没有得到改变,只为你的进程争取了点CPU资源而已,但用多线程是可以提高你上层数据调度的效率,不过不加锁显然是不现实的,如果是WINDOWS的话可以参考IOCP那个多线程异步端口的优化是怎么弄的,也可以看下哪个基于驱动消息驱动的libev框架
#8
没看懂
#9
我指的提高效率, 只单纯是UDP协议的sendto上面的. 具体可以写一个循环, 调用sendto, 发送一个1024的缓冲, 然后计算每秒可以循环多少次, 得出sendto的单线程效率, 这样死循环只得10万左右. 假如开两个线程来跑, 这样, 不单单两个线程的效率没有下降, 反而是一个线程跑10万, 两个线程跑20万. 按道理最终串行起来, 不论多少个线程, 效率不会像这样提高的.
1024B一个包, 那么1M就有1024个包, 10M就有10240个包, 通常100Mb的流量, 换算后就是12.5MB, 也就是指, 用单一个线程死循环来跑, 还跑不赢网卡的速率(虽然不知道个中过程是怎样), 但开启两个线程后, 又轻而易举的跑赢网速的.
我是想知道到底有没有必要开多个sendto线程, 只要能够让网卡满荷工作, 单线程多线程都可以. 只是不理解个中原因.
#10
通常100M网卡达不到100M的通讯速度,100M只是个接口速度,而不是最大传输数据速度,100M网卡能满荷25M就不错了,还有你那样算很多都是由于你不了解底层的东西才那样搞,操作系统是定期到硬件映射区取数据的,而这些区域大小都不大,如果你线程写的数据多,刚好系统对不上点没发出去,你的数据就堆在那,甚至丢失,还有如果你是用异步的SOCKET的话,WINDOWS SOCKET有自带线程池给你管理那些东西,不用你自己去搞,那样弄只是你个人觉得效率提高了而已,况且WINDOWS系统HAL层的东西很多都不公开,与其自己花那么多时间搞还不如用自带的,LINUX的也有现成类似WINDOWS IOCP的端口并发处理解决方案,也不用自己搞。
#11
游戏本来就属于现实中的一部分啊
#12
也就是说你认为多线程得出来的效率是假的, 似乎是快了, 但实际被硬件访问成功的不变, 也就是网卡效率不会变高也不会变低的意思了? 那我还是使单线程收发好了.
对于用不用自带功能或者用其他现成的库, 看需求吧, 现在时间多, 自己开发就可以了. IOCP和EPOLL说得那么神, 其实用起来很麻烦. 所以还是自己开发了.
IOCP, EPOLL这类说其效率高, 很多人的理解上, 只是单纯的收发速度快, 仅此而已. 但作为实际应用的一个服务器, 从接收, 到可读, 然后处理, 最后回复, 这个是一个完整的过程, 效率是要按这种完整, 具有一般性的数据来测试得出的, 很多服务器说什么1K有几万次之类的, 说老实都是废的. 1K的数据, 不具有可比性之余, 也不具有一般性, 1K, TCP就直接变成UDP来用了, TCP和UDP的分别就看不出来了. 1K, 客户端给服务器的会是1K以下, 但服务器给客户端的, 通常就不会是1K, echo 1K根本没用. 网上很多的说法都是有问题的.
IOCP, EPOLL这类只能够说IO效率很好, 但对应用层来说, 要配合这种高效的IO, 要做很多事情. 按一般情况下, IOCP对于接收完了, 处理, 然后回复, 很简单, 但假如流程上加上取消, 处理进度, IOCP就有点痛苦的(这代表一个连接被两个处理线程并行访问), 假如要提高处理速度, 要使用内存池管理缓冲, IOCP就更痛苦了(貌似用个临界区就可以了, 但效率还是不够的). EPOLL, 虽然机制来说不错, 但没有IOCP那么方便, 同样是什么东西也得要自己写的. 而且假如是采用UDP的话, 我相信什么模型都不会比死循环接收和发送来得更快.
#1
多线程调用sendto相当于多个回应同时进行,效率肯定比单线程高的。
#2
什么多个回应? 一块网卡, sendto操作同一个socket, 按道理当两个线程进入的时候就会互锁, 只有等一个线程完成操作后才轮到第二个线程处理吧? 这个sendto操作貌似也没有什么IO等待的, 起码单线程死循环的时候, 看到一个CPU核会被占用100%.
#3
你对线程的理解完全错位了。并不是说一旦线程运行就必须完全执行完成这个线程CPU才去做其它的事情,每个线程的运行都是由CPU的时间片决定的,有可能线程执行了一半的时候CPU去做其它事情了,windows核心编程第8章有详细介绍,建议楼主去看一看。
#4
CPU操作网卡是通过总线来操作的,除非你收发2个网卡,不然没用,而且收发使用不同的网卡要自己改TCP/IP协议栈底层(IP层以下的)的代码,一般不要那样做,一般提高网络连接的程序是通过修改IP层代码,主要是方法是预先通知应用层做出动作,减少传输层与IP层的逻辑连路冲突等方法来解决的,像你那样搞也可以但代价不是一般高,而且改协议栈过于底层的东西移植,测试,维护都成问题
#5
在线程和CPU核数上面, 可以确保一个线程对应有一个CPU核直接使用的, 而且线程均是无锁的形式, 所以不存在你说的问题的.
而且我想知道的问题, 还是为何sendto被多线程调用会比单线程调用效率要高
#6
按你的说法来说, 你也是认同没有必要多个线程操作同一个socket来sendto是吧? 但实际上却是多个线程调用sendto效率几倍
#7
LZ看来你还不太理解多线程,哪个只是个调度方案,而不必然提高效率,线程本身就占一定的资源开多了占资源,开多了频繁的上下文切换影响系统效率,而你想搞网络优化首先知道些硬件跟OS地层的东西,现在网卡能支持到TCP/IP到什么程度,目前网卡按硬件支持TCP/IP协议栈的程度划分主要分为:1 MAC层网卡(只取得物理连路数据,并对数据做NZ,FM0等编解码的,这个一些ARM处理器自带用CAN总线的EMAC模块差不多),2.IP层网卡(网卡能支持到TCP/IP的IP层,ICMP那些协议网卡已经做了硬件上的支持,PC端的协议栈就不用做IP层以下的工作,而交给网卡做),3.全协议网卡(至少支持到传输层的,PC只需给网卡发数据就行,怎么发网卡搞完), 而网卡跟CPU通讯要么通过总线要么通过间接连接(CPU跟内存的连接方式),读上去的数据要么通过DMA中断要么经过某个FIFO将数据交给操作系统(操作系统驱动做的),一般WINDOWS会虚拟个设备地址映射这些数据,也就是说无论你开多少线程最后都是将数据串行后放到那区域,不然的话发送数据出错甚至蓝屏,所以哪个意义不大,网络数据的吞吐量并没有得到改变,只为你的进程争取了点CPU资源而已,但用多线程是可以提高你上层数据调度的效率,不过不加锁显然是不现实的,如果是WINDOWS的话可以参考IOCP那个多线程异步端口的优化是怎么弄的,也可以看下哪个基于驱动消息驱动的libev框架
#8
没看懂
#9
我指的提高效率, 只单纯是UDP协议的sendto上面的. 具体可以写一个循环, 调用sendto, 发送一个1024的缓冲, 然后计算每秒可以循环多少次, 得出sendto的单线程效率, 这样死循环只得10万左右. 假如开两个线程来跑, 这样, 不单单两个线程的效率没有下降, 反而是一个线程跑10万, 两个线程跑20万. 按道理最终串行起来, 不论多少个线程, 效率不会像这样提高的.
1024B一个包, 那么1M就有1024个包, 10M就有10240个包, 通常100Mb的流量, 换算后就是12.5MB, 也就是指, 用单一个线程死循环来跑, 还跑不赢网卡的速率(虽然不知道个中过程是怎样), 但开启两个线程后, 又轻而易举的跑赢网速的.
我是想知道到底有没有必要开多个sendto线程, 只要能够让网卡满荷工作, 单线程多线程都可以. 只是不理解个中原因.
#10
通常100M网卡达不到100M的通讯速度,100M只是个接口速度,而不是最大传输数据速度,100M网卡能满荷25M就不错了,还有你那样算很多都是由于你不了解底层的东西才那样搞,操作系统是定期到硬件映射区取数据的,而这些区域大小都不大,如果你线程写的数据多,刚好系统对不上点没发出去,你的数据就堆在那,甚至丢失,还有如果你是用异步的SOCKET的话,WINDOWS SOCKET有自带线程池给你管理那些东西,不用你自己去搞,那样弄只是你个人觉得效率提高了而已,况且WINDOWS系统HAL层的东西很多都不公开,与其自己花那么多时间搞还不如用自带的,LINUX的也有现成类似WINDOWS IOCP的端口并发处理解决方案,也不用自己搞。
#11
游戏本来就属于现实中的一部分啊
#12
也就是说你认为多线程得出来的效率是假的, 似乎是快了, 但实际被硬件访问成功的不变, 也就是网卡效率不会变高也不会变低的意思了? 那我还是使单线程收发好了.
对于用不用自带功能或者用其他现成的库, 看需求吧, 现在时间多, 自己开发就可以了. IOCP和EPOLL说得那么神, 其实用起来很麻烦. 所以还是自己开发了.
IOCP, EPOLL这类说其效率高, 很多人的理解上, 只是单纯的收发速度快, 仅此而已. 但作为实际应用的一个服务器, 从接收, 到可读, 然后处理, 最后回复, 这个是一个完整的过程, 效率是要按这种完整, 具有一般性的数据来测试得出的, 很多服务器说什么1K有几万次之类的, 说老实都是废的. 1K的数据, 不具有可比性之余, 也不具有一般性, 1K, TCP就直接变成UDP来用了, TCP和UDP的分别就看不出来了. 1K, 客户端给服务器的会是1K以下, 但服务器给客户端的, 通常就不会是1K, echo 1K根本没用. 网上很多的说法都是有问题的.
IOCP, EPOLL这类只能够说IO效率很好, 但对应用层来说, 要配合这种高效的IO, 要做很多事情. 按一般情况下, IOCP对于接收完了, 处理, 然后回复, 很简单, 但假如流程上加上取消, 处理进度, IOCP就有点痛苦的(这代表一个连接被两个处理线程并行访问), 假如要提高处理速度, 要使用内存池管理缓冲, IOCP就更痛苦了(貌似用个临界区就可以了, 但效率还是不够的). EPOLL, 虽然机制来说不错, 但没有IOCP那么方便, 同样是什么东西也得要自己写的. 而且假如是采用UDP的话, 我相信什么模型都不会比死循环接收和发送来得更快.