io多路复用
设计高性能的网络服务器,一般多线程,但是cpu的上下文切换效率很低
那么如何用单线程来弄呢?
Select
准备文件描述符,以及最大的文件描述符
写一个while(true)
select(max+1,&rset,NULL,NULL,NULL)
&rset是一个bitmap,表征哪一个是被监听的,默认1024为
流程
1.对应rset,select,把rset交给内核,全量拷贝到内核
2.是一个阻塞函数,没有到来的时候会一直阻塞在select
3.有数据来了,将FD置位,然后select返回
4.遍历FD,判断哪些被置位,然后进行处理
特点:1.交给内核决定是否有数据(提高的效率)
2.可能是多个有数据,所以需要遍历fd集合
缺点:
1.bitmap默认大小1024
2.fdset会将其置位,然后每次都需要重新赋值,fdset不可重用
3.拷贝过程开销比较大(从用户态到内核态)
4.Select返回的时候,我们还需要遍历一遍
poll
struct pollfd{
int fd;
short events;
short revents;//对events的回馈
}
poll(pollfds,5,50000)
流程
1.工作原理和select类似
2.没有采用bitmap,采用了pollfd
3.同样为阻塞函数
4.内核置位是置的revents这个字段,然后返回
5.然后进行判断,判断revents是否有值,有的话我们把它置位为0
改善:
可以解决select的1和2 缺点
epoll
流程:
1.调用epoll_create创建一个epfd,创建完了是一个白板
2.调用epoll_ctl,在epfd上添加文件描述符+events的结构体(events和fd两个字段)
3.执行nfds=epoll_wait,epfd在用户态内核态共享的,所以不需要数据拷贝,解决了缺点3
4.wait也是阻塞函数,但如果有数据的话,先置位(重排,有数据的放在最前面),然后再返回,这个是有返回值的,返回有多少个有触发事件
5.现在只需要遍历前nfds个元素就ok了