select、poll、epoll的比较
select
优点:
能同时监听多个描述符,一旦每个描述符就绪,就能够通知应用程序进行响应的读写操作。
缺点:
- 每次调用都需要将fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大;
- 每次调用select都需要遍历所有fd,当fd集合很大时开销很大;
- select支持的文件描述符数量太小,默认是1024(或2048),可通过修改FD_SETSIZE值来更改.
poll
poll和select实现上差不多,只是描述fd集合的方式不同。poll使用pollfd结构而不是select的fd_set结构。
epoll
epoll就是对select和poll的改进。
- 针对select的第一个缺点,epoll是在
epoll_ctl
函数中,每次注册新的事件到epoll句柄(指定EPOLL_CTL_ADD
)时,会把所有的fd拷贝进内核,而不是在epoll_wait
时重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。 - 针对select的第二个缺点,epoll是在
epoll_ctl
时为每个fd指定一个回调函数,当设备就绪、唤醒等待队列上的等待者时,就会回调这个回调函数,而这个回调函数就会把就绪的fd加入到一个就绪的链表中。epoll_wait
的工作实际上就是在这个链表中查看有没有就绪的fd。 - 针对select的第三个缺点,epoll所支持的fd上限是最大解打开文件的数目,这个数字一般远远大于2048,。具体数目可以查看
/proc/sys/fs/file-max
查看,一般来说这个数目和系统内存关系很大。
水平触发(LT)和边缘触发(ET)
水平触发:文件描述符关联的读内核缓冲区非空,有数据可以读取,或者与该文件描述符关联的写缓冲区不满,用空间可以写入时,就一直发出可读/可写信号。
边缘触发:当文件描述符关联的内核读缓冲区右空转换为非空时,则发出可读信号进行通知;当文件描述符所关联的内核写缓冲区由满转换为不满时,则发出可写信号进行通知。
两者的区别在于,水平触发只要读缓冲区有数据,或写缓冲区非满状态下,就会一直触发可读/可写信号,而边缘触发则只仅仅只在状态发生改变时通知一次。