I/O的五种模型总结
文章目录
I/O的五种模型总结
1. 五种 I/O 模型
- 阻塞I/O
- 非阻塞I/O
- I/O复用
- 事件(信号)驱动I/O
- 异步I/O
为什么要发起系统调用?
因为进程想要获取磁盘中的数据,而能和硬件打交道的只能是内核,进程通知内核说我要磁盘中的数据,此过程就是系统调用。
一次I/O的完成的步骤
当进程发起系统调用时,这个系统调用就进入内核模式,然后开始I/O操作。
I/O操作分为两个步骤;
1、磁盘把数据装载到内核的内存空间,
2、内核的内存空间的数据copy到用户的内存空间中(此过程是I/O发生的地方)
以下是进程获取数据的详细图解过程;
调用过程:
①进程向内核发起一个系统调用,
②内核接收到系统调用,知道是对文件的请求,于是告诉磁盘,把文件读取出来
③磁盘接收到来着内核的命令后,把文件载入到内核的内存空间里面
④内核的内存空间接收到数据之后,把数据copy到用户进程的内存空间(此过程是I/O发生的地方)
⑤进程内存空间得到数据后,给内核发送通知
⑥内核把接收到的通知回复给进程,此过程为唤醒进程,然后进程得到数据,进行下一步操作
根据上面的步骤,我们要清楚:
I/O发生的地方才会出现阻塞或非阻塞
5种I/O 过程图解
阻塞I/O
阻塞:进程发起I/O调用,进程又不得不等待I/O的完成,此时CPU把进程切换出去,进程处于睡眠状态则此过程为阻塞I/O
阻塞I/O系统怎么通知进程?
I/O完成,系统直接通知进程,则进程被唤醒。
这里我们注意到第二阶段,因为第二阶段才是I/O发生的阶段,这个阶段我们的进程被阻塞了,所以被称为阻塞I/O。
非阻塞I/O
非阻塞:进程发起I/O调用,I/O自己知道需过一段时间完成,就立即通知进程进行别的操作,则为非阻塞I/O
非阻塞I/O,系统怎么通知进程?
每隔一段时间,问内核数据是否准备完成,系统完成后,则进程获取数据,继续执行(此过程也称盲等待)
非阻塞I/O的图解:
I/O复用
事件(信号)驱动I/O
水平触发的事件驱动机制:内核通知进程来读取数据,进程没来读取数据,内核需要一次一次的通知进程;
边缘触发的事件驱动机制;内核只通知一次让进程来读取数据,进程可以在超时时间之内随时来读取数据。
nginx就采用了边缘触发的事件驱动机制,这就是为什么nginx的并发性比apache好,当然nginx的性能比apache好,还有其它方面,如nginx支持异步I/O,mmap(内存映射)等等
实践驱动I/O图解:
异步I/O(asynchronous I/O)
前四种I/O属于同步操作,最后的一种则属于异步操作。
至于为什么,看下一节就知道了。
2. 区分总结
linux系统中,所有的设备读写都可以看做文件的读写来操作,对文件的读写一般要经过内核态和用户态的切换,正因为有切换才导致了IO有同步和异步的说法。
通常来讲IO可以分成两种:
- 网络的IO
- 来自文件或者设备的IO
并且完成IO操作可以简单的表述为两个步骤:
- 发起IO请求
- 执行IO操作
如何区分是同步IO还是异步IO呢?
看:"执行IO操作"是否阻塞
当请求被阻塞,就是同步IO,否则就是异步IO
比如说,在阻塞I/O中,进程需要发起系统调用,让内核去把磁盘的内容拷贝到内核的内存空间去,这还不够,还需要阻塞等待内核把内核的内存空间内容拷贝到用户内存空间,然后返回进行所需的数据,进程这时才得以继续运行下去,因此这个有阻塞的就是同步I/O。
而异步I/O,比如调用aio_read函数,可以直接发起系统调用,等内核把磁盘数据拷贝到内核地址,再从内核地址拷贝到用户地址,进程才会过来处理这个东西,在此前这个进程都是不会被阻塞的,因此是异步I/O。
同步IO的特点:
- 同步IO指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪。
- 同步IO的执行者是IO操作的发起者。
- 同步IO需要发起者进行内核态到用户态的数据拷贝过程,所以这里必须有阻塞
异步IO的特点:
- 异步IO是指用户进程触发I/O操作以后就立即返回,继续开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知。
- 异步IO的执行者是内核线程,内核线程将数据从内核态拷贝到用户态,所以这里没有阻塞
如何区分是阻塞IO还是非阻塞IO呢?
看:发起IO操作是否阻塞
如果阻塞直到完成,就是阻塞IO,否则就是非阻塞IO
五种I/O模型的比较:
- 阻塞I/O,第一阶段和第二阶段都被阻塞;
- 非阻塞I/O,第一阶段不阻塞,第二阶段阻塞。但是第一阶段需要轮训请求内核。
- I/O复用,第一阶段阻塞,但是不用进程阻塞,用的是select等阻塞,第二阶段阻塞。
- 事件驱动I/O,第一阶段不阻塞,通过回调函数或者信号实现,第二阶段阻塞
- 异步I/O,第一二阶段都不阻塞。