IO模型
- 几个名词
- I/O: 即输入/输出
- IO读写误区:
- 输入不是把数据直接从物理设备,读数据到内存。
- 输出,也不是直接把数据,写入到物理设备
- IO读写的实际:
- 输入是把数据从内核缓冲区复制到进程缓冲区;
- 输出是把数据从进程缓冲区复制到内核缓冲区。
- 内核缓冲区和磁盘之间的交换是由操作系统负责的
- 缓存区:
- 为了保证操作系统的稳定性和安全性,缓冲区分为:内核缓冲区、进程缓冲区。
- 由于用户程序不能访问内核空间,所以必须通过 操作系统 来间接访问内核空间,故IO操作实际上是由操作系统kernel内核完成的。
- 整个IO过程:
- 应用程序对操作系统的内核发起 IO 调用(系统调用)
- 内核等待 I/O 设备准备好数据,将数据读取到内核缓冲区
- 内核将数据从内核空间拷贝到用户空间,发送给应用程序IO完成的信号
- 4种IO模型
-
同步阻塞IO(Blocking IO)
- 应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。
-
同步非阻塞IO(Non-blocking IO)
- Java 中的 NIO 于 Java 1.4 中引入,对应
java.nio
包,提供了Channel
,Selector
,Buffer
等抽象。 - NIO 中的 N 可以理解为 Non-blocking,不单纯是 New
- 实际过程
- 应用程序会一直发起 read 调用,询问内核是否准备好内核数据。在内核开始将内核缓存区的数据复制到用户缓存区之前,应用线程都是非阻塞的
- 当应用程序可以读取数据的时候,也就是内核开始将数据复制到用户缓存区的时候,应用线程开始阻塞,直到内核返回读取完成,应用程序恢复运行。
- Java 中的 NIO 于 Java 1.4 中引入,对应
-
IO多路复用模型(IO Multiplexing),有时也称为异步阻塞IO
- 应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。所以I/O 多路复用模型** 就上场了。
- IO多路复用模型,就是通过一种新的系统调用,一个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核kernel能够通知程序进行相应的IO系统调用。
- 目前支持IO多路复用的系统调用,有 select,epoll。epoll属于 select 调用的增强版本,优化了 IO 的执行效率
- 实际过程(使用select为例)
- 多路复用IO主要用于socket连接上
- 首先应用程序将socket注册到Selector 系统调用内部的可查询socket列表中。
- 然后Selector 系统调用会负责管理内部注册的成千上万个socket的转态,如果socket的状态为可读,就设置对应的描述符。
- 在应用程序将多个socket注册之后,就会一直进行select请求,如果他注册的某一个socker可以读取的时候,就会进入阻塞转态,进入读取系统调用,等待内核将数据从内核空间复制到用户空间。
- 使用IO多路复用模型,一个应用线程就可以处理成千上万个socket请求。
-
异步IO(Asynchronous IO)
- AIO的基本流程是:用户线程通过系统调用,告知kernel内核启动某个IO操作,用户线程返回。kernel内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后续的业务操作。
- 在内核kernel的等待数据和复制数据的两个阶段,用户线程都不是block(阻塞)的。
- 应用注册IO操作完成的回调函数,到操作系统的内核。
-