IO多路复用的底层原理
IO多路复用使用两个系统调用(select/poll/epoll和recvfrom),blocking IO只调用了 recvfrom;select/poll/epoll 核心是可以同时处理多个connection,而不是更快,所以连接 数不高的话,性能不一定比多线程+阻塞IO好,多路复用模型中,每一个socket,设置为nonblocking,阻塞是被select这个函数block,而不是被socket阻塞的。
- select机制
客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、和 exceptfds(异常)。select会阻塞住监视3类文件描述符,等有数据、可读、可写、出异常 或超 时、就会返回;返回后通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的IO操 作。
优点: 几乎在所有的平台上支持,跨平台支持性好
缺点: 由于是采用轮询方式全盘扫描,会随着文件描述符FD数量增多而性能下降。 每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从 内核到用户空间) 默认单个进程打开的FD有限制是1024个,可修改宏定义,但是效率仍然慢。
- poll机制
基本原理与select一致,只是没有最大文件描述符限制,因为采用的是链表存储fd。
- epoll机制
epoll之所以高性能是得益于它的三个函数
- epoll_create()系统启动时,在Linux内核里面申请一个B+树结构文件系统,返回 epoll对象,也是一个fd
- epoll_ctl() 每新建一个连接,都通过该函数操作epoll对象,在这个对象里面修改添加 删除对应的链接fd, 绑定一个callback函数。
- epoll_wait() 轮训所有的callback集合,并完成对应的IO操作
优点: 没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个 句柄 效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降 内核和用户空间mmap同一块内存实现