Netty系列---IO多路复用技术

形成的原因:

如果一个I/O流进来,我们就开启一个进程处理这个I/O流。那么假设现在有一百万个I/O流进来,那我们就需要开启一百万个进程一一对应处理这些I/O流(——这就是传统意义下的多进程并发处理)。思考一下,一百万个进程,你的CPU占有率会多高,这个实现方式及其的不合理。所以人们提出了I/O多路复用这个模型,一个线程,通过记录I/O流的状态来同时管理多个I/O,可以提高服务器的吞吐能力

I/O多路复用的实现:

Netty系列---IO多路复用技术

我们来分析一下上面这张图

  1. 当进程调用select,进程就会被阻塞
  2. 此时内核会监视所有select负责的的socket,当socket的数据准备好后,就立即返回。
  3. 进程再调用read操作,数据就会从内核拷贝到进程。

其实多路复用的实现有多种方式:select、poll、epoll

select的基本原理:

  • 监视文件3类描述符: writefds、readfds、和exceptfds;
  • 调用后select函数会阻塞住,等有数据 可读、可写、出异常 或者 超时 就会返回
  • select函数正常返回后,通过遍历fdset整个数组才能发现哪些句柄发生了事件,来找到就绪的描述符fd,然后进行对应的IO操作
  • 几乎在所有的平台上支持,跨平台支持性好

缺点:

  • select采用轮询的方式扫描文件描述符,全部扫描,随着文件描述符FD数量增多而性能下降
  • 每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)
  • 最大的缺陷就是单个进程打开的FD有限制,默认是1024   (可修改宏定义,但是效率仍然慢)
  • static final  int MAX_FD = 1024

poll的基本流程:

  • select() 和 poll() 系统调用的大体一样,处理多个描述符也是使用轮询的方式,根据描述符的状态进行处理
  •  一样需要把 fd 集合从用户态拷贝到内核态,并进行遍历。
  • 最大区别是: poll没有最大文件描述符限制(使用链表的方式存储fd)

epoll基本原理:在2.6内核中提出的,对比select和poll,epoll更加灵活,没有描述符限制,用户态拷贝到内核态只需要一次使用事件通知,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用callback的回调机制来激活对应的fd

优点:

  • 没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄
  • 效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降
  • 通过callback机制通知,内核和用户空间mmap同一块内存实现

Linux内核核心函数:

  1. epoll_create()  在Linux内核里面申请一个文件系统 B+树,返回epoll对象,也是一个fd
  2. epoll_ctl()   操作epoll对象,在这个对象里面修改添加删除对应的链接fd, 绑定一个callback函数
  3. epoll_wait()  判断并完成对应的IO操作

缺点:编程模型比select/poll 复杂

上一篇:python学习42——IO模型


下一篇:协程,yield,i多路复用,复习