流?I/O操作? 阻塞?
(1)流
▪ 可以进⾏I/O操作的内核对象
▪ ⽂件、管道、套接字……
▪ 流的⼊⼝:⽂件描述符(fd)
(2)I/O操作
所有对流的读写操作,我们都可 以称之为IO操作。
(3)阻塞
阻塞等待 不占⽤CPU宝贵的时间⽚
⾮阻塞忙轮询 占⽤CPU,系统资源
在处理意⻅数据的接收场景时, 我们建议优先选择阻塞等待的⽅ 式, 不浪费性能资源
(4)阻塞等待缺点:
不能够很好的处理 多个(I/O)请求的问题
同⼀个阻塞,同⼀时刻只能处理⼀个流的阻塞监听
(5)多路IO复⽤
既能够阻塞等待,不浪费资源
也能够同⼀时刻监听多个IO请求的状态
解决阻塞死等待的缺点(如何解决⼤量IO请求读写的问题)
⽅法⼀ : 阻塞等待+多进程/多线程
需要开辟线程浪费资源
⽅法⼆:⾮阻塞+忙轮询
while true { for i in 流[] { if i has 数据 { 读 或者 其他处理 } } }
CPU在⼤量的做判断,while和for
cpu的利⽤率不⾼
方法三:多路IO复⽤机制 select(与平台⽆关)
监听的IO数量有限,默认是1024个
不会精准的告诉开发者,哪些IO是可读可写的,需要遍历
while true { select(流[]); //阻塞 //有消息抵达 for i in 流[] { if i has 数据 { 读 或者 其他处理 } } }
方法四:多路IO复⽤机制 epoll(Linux)
通过 /proc/sys/fd/file-max查看)
while true { 可处理的流[] = epoll_wait(epoll_fd); //阻塞 //有消息抵达,全部放在 “可处理的流[]”中 for i in 可处理的流[] { 读 或者 其他处理 } }
epoll 的API
(1) 创建EPOLL
int epoll_create(int size);
(2) 控制EPOLL
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
(3) 等待EPOLL
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout);
(4) 使⽤epoll编程主流程⻣架
触发模式
⽔平触发:
⽔平触发的主要特点是,如果⽤户在监听epoll事件,当内核有事件的时候,会拷⻉给⽤户态事 件,但是如果⽤户只处理了⼀次,那么剩下没有处理的会在下⼀次epoll_wait再次返回该事 件。
默认就是⽔平触发模式
边缘触发:
边缘触发,相对跟⽔平触发相反,当内核有事件到达, 只会通知⽤户⼀次,⾄于⽤户处理还是不处理, 以后将不会再通知。这样减少了拷⻉过程,增加了性能,但是相对来说,如果⽤户⻢⻁忘记处理,将会产 ⽣事件丢的情况。
在给事件进⾏绑定的时候,通过EPOLLET来设置