引入
为了更好的理解5种IO模型的区别,在介绍IO模型之前,我先介绍几个概念
1.进程的切换
(1)定义
为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。即从用户态(较低的3G字节)切换到内核态(最高的1G字节),非常消耗系统资源。
(2)过程
- 保存处理机上下文,包括程序计数器和其他寄存器。
- 更新PCB信息。
- 把进程的PCB移入相应的队列,如就绪、在某事件阻塞等队列。
- 选择另一个进程执行,并更新其PCB。
- 更新内存管理的数据结构。
- 恢复处理机上下文。
2.进程的阻塞
(1)定义
正在执行的进程,由于期待的某些事件未发生,由运行状态变为阻塞状态。
(2)特点
- 只有处于运行状态的进程(获得CPU)才能被阻塞
- 阻塞是主动行为
- 不占用CPU资源
3.文件描述符
(1) 定义
用于描述指向文件的引用的抽象化概念
(2) 特点
- 一个非负整数
- 本质是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表
4.缓存IO
-
IO的数据缓存在文件系统的页缓存中(先拷贝到内核的缓冲区)
-
在应用程序和内核间多次数据拷贝,带来很大的CPU开销
5.并发与并行
-
并发:同时进行的任务数
-
并行:同时工作的物理资源数量(如CPU核数)
5种IO模型
- IO的本质是socket的读取,数据先拷贝到内核的缓冲区中,然后拷贝到应用程序的地址空间(进程)
1.BIO(blocking IO):同步阻塞 I/O
(1)过程
分析:从上图可以看到在整个过程中,当用户进程进行系统调用时,内核就开始了I/O的第一个阶段,准备数据到缓冲区中,当数据都准备完成后,则将数据从内核缓冲区中拷贝到用户进程的内存中,这时用户进程才解除block的状态重新运行。
(2)实例
-
Blocking I/O是在I/O执行的两个阶段都被block了。
-
例如:我要去饭堂吃饭,这时饭堂的人很多,我就得排队买饭,排队的时间被浪费了,
(3)特点
- 能够及时返回数据,无延迟
- 性能下降
2.NIO(nonblocking IO):同步非阻塞 I/O
(1)过程
分析:从上图可以看到在I/O执行的两个阶段中,用户进程只有在第二个阶段被阻塞了,而第一个阶段没有阻塞,但是在第一个阶段中,用户进程需要盲等,不停的去轮询内核,看数据是否准备好了。
(2)实例
-
nonblocking I/O是在I/O执行的第二个阶段(数据复制)被block了,而第一个阶段并未阻塞(数据准备)。
-
例如:我要去饭堂吃饭,这时饭堂的人很多,一般来说我需要排队买饭,但我们饭堂的管理最近变的比较人性化,你点完饭后,会给你一个号码,但饭堂噪声很大,我不得不频繁的询问我的饭是否做好了,但是我可以利用之前排队的时间去买瓶饮料喝!
(3)特点
- 拷贝数据的整个过程,进程仍然是阻塞的
- 需要不断询问数据是否准备好了
- 能够在等待任务完成的过程中处理其他事件
- 由于需要轮询,所以延迟会增加
3.多路复用IO( IO multiplexing)
(1)过程
分析:
-
从上图可以看到在I/O复用模型中,由于同步非阻塞方式需要不断主动轮询,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间,而 “后台” 可能有多个任务在同时进行,
-
如果循环查询多个任务的完成状态,只要有任何一个任务完成,就去处理它。轮询不是进程的用户态。这时 “IO 多路复用”就出现了。即UNIX/Linux 的 select、poll、epoll,
-
IO多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。
-
从整个IO过程来看,他们都是顺序执行的,因此可以归为同步模型(synchronous)。都是进程主动等待且向内核检查状态
(2)实例
-
多路复用I/O执行的两个阶段用户进程都是阻塞的,但是两个阶段是独立的。
-
例如:我要去饭堂吃饭,这时饭堂的人很多,点完饭后,我会拿到一个号码,以前我不得不频繁的询问我的饭做好了没,但是最近饭堂安装了一块电子显示屏,你的饭好了就会在屏上显示出来,这时候我就不用频繁的去问了,直接看电子显示屏就醒了,然后我就可以利用这个时间去超市买个牙膏了。
(3)特点
-
select/poll调用后会阻塞进程,但可以同时阻塞多个IO事件操作(文件描述符),有数据可读或可写(就绪事件),就通知用户进程。
-
select 需要每次注册事件(轮询),而epoll不需要每次注册事件(没有轮询,回调函数)
-
IO多路复用阻塞在select/epoll的系统调用之上的,而真正的IO系统调用如recvfrom是非阻塞的。
(4)适用场景
-
服务器需要同时处理多个处于监听状态或连接状态的套接字
-
服务器需要处理多种网络协议的套接字
4.信号驱动I/O( signal driven IO)
(1)过程
分析:从上图可以看出,只有在I/O执行的第二阶段阻塞了用户进程,而在第一阶段是没有阻塞的。该模型在I/O执行的第一阶段,当数据准备完成之后,会主动的通知用户进程数据已经准备完成,即对用户进程做一个回调。该通知分为两种,一为水平触发,即如果用户进程不响应则会一直发送通知,二为边缘触发,即只通知一次。
(2)实例
-
信号驱动I/O执行的第一阶段阻塞,而第二阶段不阻塞。
-
例如:我要去饭堂吃饭,这时饭堂的人很多,点完饭后,我会拿到一个号码,虽然说饭堂安装了一块电子显示屏,但我在玩手机时还不得不抬头看一下显示屏上有我的号码没,最近饭堂买了一个大喇叭,哪个号码好了,卖饭的阿姨就会用喊,虽说饭堂有点吵,但这个声音还是可以听到的,这样我就可以专心的低头玩手机了。
5.异步 I/O(asynchronous IO)
(1)过程
分析:从上图可以看出,在该模型中,当用户进程发起系统调用后,立刻就可以开始去做其它的事情,然后直到I/O执行的两个阶段都完成之后,内核会给用户进程发送通知,告诉用户进程操作已经完成了。
(2)实例
-
异步 I/O执行的两个阶段都不会阻塞。
-
例如:我要去饭堂吃饭,估计这会饭堂的人很多,但最近我们饭堂可以叫外卖了,这样就省事多了,我直接打个电话,订份饭送到我们宿舍,而我现在就可以利用原来去饭堂路上和等饭的时间写博客了。
-
这就是同步和异步的区别,原来我得亲自去饭堂买饭,而现在我可以在宿舍叫外卖。
(3)特点
- 读写操作由内核完成,完成后内核将数据放到指定的缓冲区,通知应用程序来取。
总结
-
阻塞IO和非阻塞IO的区别:数据准备的过程中,进程是否阻塞。
-
同步IO和异步IO的区别:数据拷贝的过程中,进程是否阻塞。
本人才疏学浅,若有错,请指出,谢谢!
如果你有更好的建议,可以留言我们一起讨论,共同进步!
衷心的感谢您能耐心的读完本篇博文!
参考资料:聊聊Linux 五种IO模型