1. select:
监听多个文件描述符(当文件描述符条件不满足时,select会阻塞),当某个文件描述符状态改变后,将该文件描述符添加到对应返回的列表
调用:
fd_r_list, fd_w_list, fd_e_list
=
select.select(rlist, wlist, elist, [timeout])
参数:三个序列、一个超时时间
- rlist: wait until ready for reading
- wlist: wait until ready for writing
- elist: wait for an “exceptional condition”
- timeout: 超时时间,超时时间为空,则select会一直阻塞,直到监听的句柄发生变化
返回值:三个列表
- 当rlist序列中的fd满足“可读”条件时,则获取发生变化的fd并添加到fd_r_list中
- 当wlist序列中含有fd时,则将该序列中所有的fd添加到 fd_w_list中
- 当elist序列中的fd发生错误时,则将该发生错误的fd添加到 fd_e_list中
缺点:
- 事件循环中只要select监听的满足条件的fd状态发生改变,就会调用select函数,此过程需要将监听的所有fd从用户态拷贝到内核态,随监听的fd数量增加开销增大
- select只能知道有fd变化,却不知道具体是谁,所以需要遍历所有fd,当fd数量很大时,开销增大
- select可监听的fd最大数量有限制(1024)
优点:
跨平台(windows、unix、linux都能用)
2. poll(过渡):
优点:
解决了select监听最大数量限制的问题
3. epoll:
优点:
解决大量并发连接中少量活跃情况下系统CPU利用率问题(
- epoll_create创建epoll句柄
- epoll_ctl注册/删除待监听事件
- epoll_wait等待事件产生
)
- epoll_ctl每次注册新的事件到epoll句柄中时,会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝,保证了每个fd在整个过程中只会拷贝一次
- epoll_ctl遍历fd,为每个fd指定回调函数,客户端就绪,唤醒等待队列的等待者,调用回调函数把就绪的fd加到就绪链表,epoll_wait直接遍历就绪链表查看就绪的fd
- 没有最大监听数量限制
*水平触发、边缘触发
水平触发:电信号为0或1时触发;即只要满足某个条件就触发(监听的fd有可读写事件发生,但未读写完,下次还会通知)--select、epoll
边缘触发:电信号由0变为1时触发(或1变为0);即状态变化时触发(监听的fd有可读写事件发生,但未读写完,下次不会通知,除非再有新的读写状态变化时触发)--epoll