IO 多路复用
I/O 是指网络 I /O ,多路指多个 TCP 连接,复用指一个或几个线程。
简单来说:就是使用一个或者几个线程处理多个 TCP 连接,最大优势是减少系统开销,不必创建过多的线程进程,也不必维护这些线程进程
#### select
文件描述符 writefds、readdfs、exceptfds
30w个连接会阻塞住,等数据可读、可写、出异常、或者超时返回
select 函数正常返回后,通过遍历 fdset整个数组才能发现哪些句柄发生了事件,来找到就绪的描述符fd,然后进行对应的 IO操作,几乎在所有的平台上支持,跨平台支持性好
缺点:
select采用轮询的方式扫描文件描述符,全部扫描,随着文件描述符 FD 数量增多而性能下降。
每次调用 slect (),需要把 fd集合从用户态拷贝到内核态,并进行遍历(消息传递都是内核到用户空间)
最大缺陷就是单个进程打开的FD 有限制,默认是 1024
#### poll
基本流程和 select差不多,处理多个描述符也是轮询,根据描述符的状态进行处理,一样需要把fd集合从用户态拷贝到内核态,并进行遍历。
区别是poll 没有最大文件描述符限制(使用链表方式存储fd)
#### epoll
没有描述符限制,用户态拷贝到内核态只需要一次使用事件通知,通过epoll_ctl注册fd,一旦该fd 就绪,内核就采用callback机制激活对应的fd
优点:
1. 没有fd限制,所支持的 FD 上限是操作系统的最大文件句柄数(65535),1G 内存大概支持 10W 句柄,支持百万连接的话,16G 内存就可以搞定
2. 效率高,使用回调通知而不是轮询方式,不会随着 FD 数目增加效率下降
3. 通过 callback 机制通知,内核和用户空间 mmap 同一块内存实现
缺点:
编程模型比 select / poll 复杂
linux内核核心函数
1. epoll_create() 系统启动时,会向linux内核申请一个文件系统,b+树,返回epoll 对象,也是一个fd
2. epoll_ctl() 操作epoll对象,在这个对象里面修改添加删除对应的链接fd,绑定一个callback函数
3. epoll_wait() 判断并完成对应的 IO 操作
例子:100W 个连接,1W 个活跃,在 select ,poll,epoll中怎么样表现
select :不修改宏定义,需要 1000 个进程才能支持 100W 连接
poll:100W连接,遍历都响应不过来,还有空间的拷贝消耗大量的资源
epoll: 不用遍历fd,不用内核空间和用户空间数据的拷贝
如果 100W 个连接中,95W 活跃,则 poll 和 epoll差不多
公众号进入网站体验更佳

