Linux IO 模型
普通输入操作的步骤:
- 等待数据准备好
- 从内核向进程复制数据
网络数据输入包含的步骤:
- 等待数据从网络送达, 到达后被复制到内核缓冲区
- 把数据从内核缓冲区复制到应用程序缓冲区
同步
阻塞式 IO
使用系统调用, 并一直阻塞直到内核将数据准备好, 之后再由内核缓冲区复制到用户态, 在等待内核准备的这段时间什么也干不了.
非阻塞式 IO
内核在没有准备好数据的时候会返回错误码, 而调用程序不会休眠, 而是不断轮询询问内核数据是否准备好.
IO 多路复用
类似于非阻塞, 只不过轮询不是由用户线程去执行, 而是由内核去轮询.
IO 多路复用至少有两次系统调用, 如果只有一个代理对象, 性能不如非阻塞式 IO, 但是由于它可以同时监听很多套接字, 所以性能会比较好.
多路复用包括:
- select: 线性扫描所有监听的文件描述符, 不管他们是不是活跃的. 有最大数量限制.
- poll: 同 select, 不过数据结构不同, 需要分配一个 pollfd 结构数组维护在内核中. 它没有大小限制, 不过需要很多复制操作.
- epoll: 用于代替 poll 和 select, 没有大小限制. 使用一个文件描述符管理多个文件描述符, 使用红黑树存储. 同时用事件驱动代替了轮询.
信号驱动式 IO
使用信号代替轮询, 内核在数据准备就绪时通过信号来进行通知.
异步
异步 IO 依赖信号处理程序来进行通知. 与前面 IO 模型不同的时: 前面的都是数据准备阶段的阻塞与非阻塞, 异步 IO 模型通知的是 IO 操作已经完成, 而不是数据准备完成.
参考
Java IO 模型
BIO
即 java.io
包.
它是基于流模型实现的, 交互的方式是同步, 阻塞方式.
NIO
Java1.4 引入了 java.nio
包.
提供了 Channel, Selector, Buffer 等新的抽象, 可以构建多路复用的, 同步非阻塞 IO 程序.
AIO
Java1.7 引入了 AIO(Asynchronous IO)