I/O多路转接复用机制---select,poll,epoll
Posted 梅诺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了I/O多路转接复用机制---select,poll,epoll相关的知识,希望对你有一定的参考价值。
首先提出一个比较基础的但对后面理解有帮助的知识点,就是I/O模型有哪几种?一次I/O的过程是怎样的?
(1)按照等待方式的不同,我们可以将I/O模型分为5类,如下表格:
阻塞I/O |
非阻塞I/O |
多路复用I/O |
信号驱动I/O |
异步I/O |
1.买好多鱼竿,将他们放在水里,然后自己去干别的事情,隔一段时间来查看鱼上钩的情况就好,这种方式就是多路复用方式;
2.在鱼竿上系一个铃铛,他可以去干别的事情,听到铃铛响之后再来查看鱼上钩的情况就好,这种方式就是信号驱动方式;
3.钓鱼的人花钱雇人去给他钓鱼,他只需拿到最后上钩的鱼的结果就好,这种方式就是异步方式。
(这样理解是不是就能够好理解一点了呢!)
(2)一般来说,一次完整I/O分为两部分:等待数据就绪和搬迁数据
我们可以大胆猜想,在整个程序运行的过程中一次I/O主要花费在哪个步骤?没错,就是等待数据就绪的步骤。那么,我们下面所提出的I/O多路转接复用就是将等待数据就绪的过程单独拿了出来进行性能上的优化。
那么为何会有I/O多路转接复用这个概念?为了更好地理解这个问题,先来举一个比较形象的例子,当然我自己也是这样极理解记忆的。
机场有好多航班需要调度员了解当前状况后进行调度,那在调度之前是所有航班的信息是需要被统计的,这些工作难道逐航班派人去核对然后报告调度室吗?(这就相当于单进程调度)显然效率太低了嘛!所以最后解决问题的方法就是一个人员管理一组航班,最后将信息报告给调度室。在这里,我们可以把每一个航线当成是一个I/O流, 那个人员就可以理解为服务端的sock,即实现了单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。)
提出I/O多路转接复用的目的,其实就是为了提高服务器的吞吐能力,大大优化服务性能。
当然,select,poll,epoll都是IO多路复用的机制。所谓I/O多路复用机制,就是说通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作,它们三者都属于同步I/O.
它们三者区别如下表:
机制类型名 | 特点 | 缺点 |
select | (1)要监控的文件描述符个数由系统决定(sizeof(文件描述符集) (2)读或者写文件描述符加入到select监控时,必须要创建数组来保存放到select监控集中的文件描述符 | (1)每次调用select之前,都必须将文件描述符集合从用户区拷贝到内核区(2)每次调用select是都要在内核区遍历一遍读或者写文件描述符 (3)select支持的文件描述符受系统限制 |
poll | (1)用于监控的文件描述符没有大小的限制,任用户定义(2)有自己的数据结构用来设置状态(POLLIN/POLLOUT) | 虽然系统的句柄没有受到限制,但是系统等待花费的代价是随句柄数量的增多而上升的 |
epoll | (1)句柄数量不受系统的限制 (2)和上面两种方法相比有三个操作函数,epoll_create,epoll_ctl,epoll_wait (3)开始定义的句柄,使用完后必须关闭 |
目前这种机制已经算是高性能的了 |
这里,着重说明一下epoll的三个函数:
int epoll_create(int size):创建一个epoll的句柄,使用完epoll后,必须调用close()关闭,否则就有可能耗尽系统的句柄,如此一来,岂不是和select和poll使用句柄的副作用类似了!
int epoll_ctl(文件描述符集,int op,文件描述符,状态结构体):这个函数用来注册监听的事件的类型op代表动作,在这里使用三个宏来表示:EPOLL_CTL_ADD:注册新的文件描述符到文件描述符集中;EPOLL_CTL_MOD:修改已经注册好的文件描述符所代表的监听事件;EPOLL_CTL_DEL:从文件描述符集中删除文件要监听的文件描述符。
int epoll_wait(文件描述符集,状态结构体,maxenvent,int timeout):收集在epoll监控的时间中已经发送的事件。其中maxevents不能大于创建的epoll_create()时的size.调用这个函数后返回一个代表就绪面描述符数量的值。
epoll_ctl函数:每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
epoll只在epoll_ctl时把当前的句柄添加进文件描述符集中,并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表。
epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd。
以上是关于I/O多路转接复用机制---select,poll,epoll的主要内容,如果未能解决你的问题,请参考以下文章
I/O多路转接模型 [select] [poll] [epoll]
I/O多路转接模型 [select] [poll] [epoll]
I/O--多路复用的三种机制Select,Poll和Epoll对比