谈谈 IO 模型、NIO 和多路复用

一共有五种IO模型

  • 阻塞IO模型
  • 非阻塞IO模型
  • IO多路复用模型
  • IO模型之信号驱动模型
  • IO 模型之异步IO(AIO)

NIO(非阻塞IO模型)

NIO,即Non-Blocking IO,是非阻塞IO模型。非阻塞IO的流程如下:

图片


  1. 应用进程向操作系统内核,发起recvfrom读取数据。
  2. 操作系统内核数据没有准备好,立即返回EWOULDBLOCK错误码。
  3. 应用程序进程轮询调用,继续向操作系统内核发起recvfrom读取数据。
  4. 操作系统内核数据准备好了,从内核缓冲区拷贝到用户空间。
  5. 完成调用,返回成功提示。

NIO(非阻塞IO模型)存在性能问题,即频繁的轮询,导致频繁的系统调用,同样会消耗大量的CPU资源。可以考虑IO复用模型去解决这个问题。

IO多路复用模型

IO多路复用就是,等到内核数据准备好了,主动通知应用进程再去进行系统调用。

IO复用模型核心思路:系统给我们提供一类函数(如我们耳濡目染的select、poll、epoll函数),它们可以同时监控多个fd的操作,任何一个返回内核数据就绪,应用进程再发起recvfrom系统调用。

IO多路复用之select

应用进程通过调用select函数,可以同时监控多个fd,在select函数监控的fd中,只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时应用进程再发起recvfrom请求去读取数据。

图片


非阻塞IO模型(NIO)中,需要N(N>=1)次轮询系统调用,然而借助select的IO多路复用模型,只需要发起一次询问就够了,大大优化了性能。

但是呢,select有几个缺点:

  • 监听的IO最大连接数有限,在Linux系统上一般为1024。
  • select函数返回后,是通过遍历fdset,找到就绪的描述符fd。(仅知道有I/O事件发生,却不知是哪几个流,所以遍历所有流)

因为存在连接数限制,所以后来又提出了poll。与select相比,poll解决了连接数限制问题。但是呢,select和poll一样,还是需要通过遍历文件描述符来获取已经就绪的socket。如果同时连接的大量客户端,在一时刻可能只有极少处于就绪状态,伴随着监视的描述符数量的增长,效率也会线性下降。

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java