Linux-I/O多路复用(select,poll,epoll)
select
函数原型
select系统调用会阻塞进程,当有数据到来系统将fd_set对应位置位,select函数返回.select会将fd_set拷贝到内核.其实select只能返回一个准备好的文件描述符,如果在主线程对相应的文件描述符做操就会阻塞,使得其他准备好的文件描述符得不到处理,因此就有了Reactor模型.
#include <sys/select.h>
int select(int nfds, fd_set *rdfds, fd_set *wtfds,
fd_set *exfds, struct timeval *timeout)
缺点
- fd_set组成的bitmap只有1024个
- fd_set不可重用,每次都要重新设置fd_set
- 拷贝fd_set有开销
- 需要遍历fd_set
poll
函数原型
poll使用了pollfd结构体,有数据到来系统将polfd.revents置位
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
对select改进
- 使用pollfd数组,可以管理大于1024个文件描述符
- pollfd可重用
- 遍历范围变小(pollfd数组),poll返回准备好的文件描述符个数
epoll
函数原型
有数据到来系统将epfd用重排来置位(将有数据的epfd放在数组前面)
//创建size个监听,返回一个红黑树的文件描述符epfd
int epoll_create(int size)
//epfd控制
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
//等待epfd准备好
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
使用以下命令查看可以使用的pollfd数量
cat /proc/sys/fs//file-max
改进
- epfd用户态与内核态共用
- 遍历范围变小(准备好的epfd数组),epoll_wait返回准备好的文件描述符个数
触发模式
- 边沿触发(ET):文件描述符从无数据状态到有数据状态epoll才触发
- 水平触发(LT):文件描述符有数据epoll就触发
应用
- redis
- nginx
- java NIO(Linux系统)