这个问题面试经常会被问道,赶紧总结一下
select、poll、epoll都是IO多路复用的机制,先是监听多个文件描述符FD,一旦某个FD就绪,就可以进行相应的读写操作。但是select、poll、epoll本质都是同步I/O,他们都需要在读写事件就绪之后自己负责读写,即这个读写过程是阻塞的
1 select/poll
select缺点:
【1】每次调用select都需要把fd从用户态拷贝到内核态,开销比较大
【2】每次都需要在内核遍历传入的fd
【3】select支持文件数量比较小,默认是1024
poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,就不赘述了
2 epoll牛在哪里?
select/poll只提供了一个函数,selct/poll函数,但是epoll一下子就提供了3个函数,真是人多力量大,难怪这么强,如下3个函数:
epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句 柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。
优点:
【1】每次注册新事件到epoll句柄都会把所有的fd拷贝进来,而不是在epoll_wait中重复拷贝,这样确保fd只会被拷贝一次
【2】epoll不是想select/poll那样每次都把fd加入等待队列中,epoll把每个fd指定一个回调函数,当设备就绪时,唤醒等待队列的等待者就会调用其的回调函数,这个回调函数会把就绪的fd放入一个就绪链表。epoll_wait就是在这个就绪链表中查看有没有就绪fd
【3】epoll没有fd数目限制
总结:
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在 epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内 部定义的等待队列)。这也能节省不少的开销。
版权声明:本文为博主原创文章,未经博主允许不得转载。