Linux IO 模型

普通输入操作的步骤:

  • 等待数据准备好
  • 从内核向进程复制数据

网络数据输入包含的步骤:

  • 等待数据从网络送达, 到达后被复制到内核缓冲区
  • 把数据从内核缓冲区复制到应用程序缓冲区

同步

阻塞式 IO

使用系统调用, 并一直阻塞直到内核将数据准备好, 之后再由内核缓冲区复制到用户态, 在等待内核准备的这段时间什么也干不了.

I/O - 图1

非阻塞式 IO

内核在没有准备好数据的时候会返回错误码, 而调用程序不会休眠, 而是不断轮询询问内核数据是否准备好.

I/O - 图2

IO 多路复用

类似于非阻塞, 只不过轮询不是由用户线程去执行, 而是由内核去轮询.
IO 多路复用至少有两次系统调用, 如果只有一个代理对象, 性能不如非阻塞式 IO, 但是由于它可以同时监听很多套接字, 所以性能会比较好.

多路复用包括:

  • select: 线性扫描所有监听的文件描述符, 不管他们是不是活跃的. 有最大数量限制.
  • poll: 同 select, 不过数据结构不同, 需要分配一个 pollfd 结构数组维护在内核中. 它没有大小限制, 不过需要很多复制操作.
  • epoll: 用于代替 poll 和 select, 没有大小限制. 使用一个文件描述符管理多个文件描述符, 使用红黑树存储. 同时用事件驱动代替了轮询.

信号驱动式 IO

使用信号代替轮询, 内核在数据准备就绪时通过信号来进行通知.

异步

异步 IO 依赖信号处理程序来进行通知. 与前面 IO 模型不同的时: 前面的都是数据准备阶段的阻塞与非阻塞, 异步 IO 模型通知的是 IO 操作已经完成, 而不是数据准备完成.

I/O - 图3

参考

Java IO 模型

BIO

java.io 包.
它是基于流模型实现的, 交互的方式是同步, 阻塞方式.

NIO

Java1.4 引入了 java.nio 包.
提供了 Channel, Selector, Buffer 等新的抽象, 可以构建多路复用的, 同步非阻塞 IO 程序.

AIO

Java1.7 引入了 AIO(Asynchronous IO)