我的理解多路复用select epoll poll

从开始学习编程后,我就想开一个 Hello World 餐厅,由于一开始资金不足,所以只能开一个古老的小客栈。 

客栈运营了几天,我发现我们的客栈存在着一个问题 

我们的厨师只负责炒菜,炒好了放在一边继续炒其他菜,所以店小二必须经常进出厨房,一方面看看菜到底炒好了没有,如果炒好的话,就要把菜端出来,另一方面他必须得站在外面等候客人的其他需求。并且重要的是只有一个小二,他同时只能服务一个客人,其他客人必须等待 
在客栈客人少的时候问题还不明显,有时候突然来个十几个客人,看到没人招待他,掉头就走了。 

第一个解决方案(多线程) 

给每一位顾客配备一名店小二。 
这样一来,每一个顾客都有专门的小二负责,厨师一炒好菜,小二就将菜第一时间送到客人桌上,这样一来,客人的体验提升了很多,大家都非常满意,我客栈的名声也越来越好。 

随着名声越来越好,客人也越来越多,渐渐地我发现,好像有什么地方不对。 

随着客人越来越多,我必须招更多的店小二,支付更多的费用在小二身上,我发现,有时候付给员工的费用都比我赚的还多 
第二个解决方案(select) 

我将客栈进行改造,按照桌数区分,分为 1 2 3 4 四个区,每个区招一名店小二,来服务所在区的客人,并且对厨师进行了简单的培训,让他再炒好菜后大喊一声,有菜炒好了 
这次简单升级后,我的客栈现在只有 4 个小二了,每个小二负责自己的区域,并且厨师炒好菜后,他大喊一声,来来来,菜炒好了,然后比如小二 1 号进入厨房,把菜端到他对应的区域挨个问,这菜是谁点的。 

随着我的客栈越来越大越来越大,为了节省成本,我并没有再招更多的小二,依然是那四个小二。 

直到有一天,1 区的客人爆满,达到了 1024 个了,那一天,我看着 1 区的小二每一次上菜几乎都是跑的,并且他告诉我,如果再多来一个客人,他就要挂了。 
第三个解决方案(poll) 

好吧,那个小二体力上好像跟不上节奏,所以我派人连夜赶工做了传说中的木牛流马来当店小二,这样一来,即使是 10240 个客人,一个木牛流马就 hold 住了 
人数上限问题已经解决了,但是现在依然存在问题。 

由于人数太多,每次要将做好的菜送到对应的客人桌上,必须挨个询问过去,这个步骤太慢了,很多次客人都不愿意等待而走掉了。 
最终解决方案(epoll) 

对木牛流马进行加工,使其可以记录每一个客人点的菜,然后厨师炒好菜后,只要报上菜名,木牛流马根据记录的订单,自动就将对应的菜端到客人桌中 
有了这个解决方案,那么当一盘菜炒好后,就不必挨个确认是谁的菜了,如果新来了客人,同样只要记录下客人的菜单,提交给厨师,然后木牛流马又可以去招待其他客人了,当菜炒好后,直接就将菜送到客人那里了。 

至此,生意兴荣,长盛不衰。 

总结 



 

1.Select:在多个i/o

  select的参数里其中有:nfds监控I/O最大数,他的底层会用轮询的方式监控这个大小的I/O,剩下,select将I/O进行分类,可读,可写的,错误的,实际上是一long类型的数组

返回现在可以活动的个数,把没有可以活动的删掉,判断哪个I/O可以活动需要代入集合里面看有没有,可以设置时间,如果时间内没有活动返回个数的话

2. I/O复路中select和epool 以及poll区别

(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升

(2)对于epoll系统调用,当poll唤醒等待者时,epoll顺势记录了唤醒者的信息到红黑树红黑树是内核lib文件夹下的一个实现,也就是一个库中提供的数据结构它的特点就是保持了较好的平衡性,所以查找和删除都不会太慢。它是AVL树的一个折中,没有AVL树高度限制那么严格,但是操作速度会有相对提高对于select调用来说,它只是简单的唤醒,这个简单的代价就是在do_select函数中有一个罕见的三重for循环

(3)Select(select支持的文件描述符数量太小了,默认是1024)poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销poll和epoll适用于关心描述符个数多的应用程序。其中epoll对于每次只有很少描述符就绪很有优势(采用回调机制监测描述符就绪)。

 

3. epoll的底层

首先epoll_create创建一个epoll文件描述符,底层同时创建一个红黑树,和一个就绪链表;红黑树存储所监控的文件描述符的节点数据,就绪链表存储就绪的文件描述符的节点数据;epoll_ctl将会添加新的描述符,首先判断是红黑树上是否有此文件描述符节点,如果有,则立即返回。如果没有, 则在树干上插入新的节点,并且告知内核注册回调函数。当接收到某个文件描述符过来数据时,那么内核将该节点插入到就绪链表里面。epoll_wait将会接收到消息,并且将数据拷贝到用户空间,清空链表。对于LT模式epoll_wait清空就绪链表之后会检查该文件描述符是哪一种模式,如果为LT模式,且必须该节点确实有事件未处理,那么就会把该节点重新放入到刚刚删除掉的且刚准备好的就绪链表,epoll_wait马上返回。ET模式不会检查,只会调用一次

 

4. 使用场景

  Select/poll(): 你要跨平台,因为epoll只支持linux,socket数目少于1000个,大于1000但是socket寿命比较短的,没有其他线程干扰的时候

  epoll:  1.多线程,多连接。在单线程还不如poll 2.大量线程监控1000上, 3.相对长寿命的连接。系统调用会很耗时。 4 .linux依赖的事情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值