I/O复用:select、poll、epoll区别
select 和poll的区别:
select:
select的触发方式是水平触发(LT),应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。
创建数组,保存描述符
(一次while要做的事:)
- 清空集合FD_ZERO
- 遍历数组,将fd写入fdset集合中(由于内核对fd_set的修改,应用程序下次调用select前需要重置fd_set集合。),循环次数由描述符个数决定
- 将fdset集合传给select(系统调用)---->从用户空间向内核空间拷贝(select需要复制大量的句柄数据结构,产生巨大的开销);
- 内核实现是轮询方式(一个一个检查,检测那些事件就绪),将其中就绪的描述符返回给应用程序,检测就绪事件的算法的时间复杂度为o(n),描述符越多,耗时越长,性能越差
- select返回后,需遍历所有描述符,找到就绪的描述符(FD_ISSET)
相比select模型,poll使用链表保存文件描述符,因此没有了监视文件数量的限制
poll:
poll通过把文件描述符和事件定义在pollfd中,任何事件都被统一处理,从而使得编程接口简洁许多。并且内核每次修改的是pollfd结构体的revents成员,而events成员保持不变,因此下次调用poll时无须重置pollfd结构体类型的事件集参数。
- 不需要每次清空数组,只要需要动态维护住即可
- 将数组传给Poll(系统调用)---->从用户空间向内核空间拷贝
- 内核实现是轮询方式(一个一个检查),将其中就绪的描述符返回给应用程序,检测就绪事件的算法的时间复杂度为o(n),描述符越长,耗时越长
- Poll返回后,需遍历所有描述符,找到就绪的fd
selec 和poll都只能在相对低效的LT模式,而epoll可以工作在ET高校模式
select和poll都没有从本质上解决,当描述符数量过多时,效率越低的情况
epoll:
创建一个内核事件表, 把用户关心的文件描述符上的事件都放在内核里的事件表中,从而无须像select,poll那样每次调用都要重复传入文件描述或事件集,但epoll需要使用一个额外的文件描述符,来唯一标识内核中创建的这个内核事件表。
select、poll、epoll区别: