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系統)