浅谈IO模型

141 阅读6分钟

一、什么是IO?

对于磁盘IO,将数据从磁盘中读取数据到内存空间为输入input,相反地将数据从内存空间写入磁盘就是输出output

何为IO?简单而言就是输入输出,I/O=input/output。对计算机而言,IO是计算机核心与其他设备间数据迁移的过程。

二、IO基础概念

🌟 同步与异步

同步和异步是针对应用程序和内核的交互而言的

  • 同步:用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪。即A调用B,B在处理完之前不会通知A,只有等待处理完之后才会通知A
  • 异步:用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。即A调用B,B在接到请求后先告诉A我已经接到请求了,然后异步去处理,处理完之后通过回调等方式再通知A
  • 判断窍门:是否需要马上返回结果

🌟 阻塞与非阻塞

阻塞与非阻塞是针对用户就和内核空间IO操作的方式而言的

  • 阻塞:用户空间通过系统调用和内核空间发送IO操作时,该调用是堵塞的需要等待的。即A调用B,A需要一直等着B的返回,期间不能进行其他操作
  • 非阻塞:用户空间通过系统调用和内核空间发送IO操作时,该调用是不堵塞的,直接返回的,只是返回时,可能没有数据而已。即A调用B,A无需一直等着B的返回,可以进行其他操作
  • 判断窍门:是否需要一直等待

🌟 用户空间以及内核空间

在Linux中,虚拟内存被操作系统划分为两块:内核空间和用户空间,内核空间是操作系统内核访问的内存区域,是受保护的内存空间,用户空间是用户应用程序访问的内存区域。处于安全方面的考虑,这两块的内存区域是相互隔离的,用户空间的崩溃不会影响到内核空间。

用户空间不能直接调用系统资源,可以通过系统调用(system call)向内核发起请求,调用系统资源(通过系统调用,可以从用户空间切换到内核空间)

🌟 IO的分类

IO可以分为内存IO网络IO磁盘IO,我们通常的IO指后两种。

I/O按照设备来分可以分为两种:一种是网络IO,也就是通过网络进行数据的拉取和输出;另一种是磁盘IO,主要是对磁盘进行读写工作。

磁盘IO以及网络IO之间的对比:
磁盘IO的主要延迟=机械转动延时+寻址延时+块传输延时
网络IO的主要延迟=服务器响应+带宽限制+网络延时+跳转路由延时+本地接收延时

🌟 一次IO操作的过程

应用程序的一次IO操作主要可以分为两个阶段:

  • IO调用:应用程序进程向操作系统内核发起调用
  • IO执行:操作系统内核完成IO操作

IO调用由进程发起(用户态),IO执行是系统内核的工作(内核态)

操作系统内核完成IO包括两个阶段:

  • 数据准备:内核等待IO设备准备好数据
  • 数据拷贝:将数据从内核缓冲区拷贝到用户进程缓冲区

IO流程

三、IO模型

同步阻塞IO:Blocking IO,传统IO模型

同步非阻塞IO:Non-blocking IO,默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK

IO多路复用:IO Multiplexing,并发式同步阻塞IO,使用Reactor设计模式,例如Java中的Selector、Linux中的epoll

异步IO:Aysnchronous IO,异步非阻塞IO,使用Proactor设计模式

(1)同步阻塞IO模型

用户空间的进程发起IO系统调用后,会导致进程被阻塞,转到内核空间处理,直到数据准备好,并将数据从内核复制到用户进程,整个IO处理完毕后才返回成功提示。这个过程,整个进程被阻塞,不能处理其他IO。

IO模型-阻塞IO

使用场景:阻塞Socket、Java BIO

调用应用程序处于一种不再消费CPU而只是简单等待相应的状态;如果内核数据一直没准备好,用户进程将会一直阻塞

(2)同步非阻塞IO模型

用户空间的进程发起IO系统调用后,内核会立马返回结果给进程,如果内核数据准备好,返回数据,否则返回一个错误信息,用户进程不会一直被阻塞,而是通过轮询的方式再次进行请求,直到数据准备好,在将内核数据拷贝到用进程。(拷贝数据的过程仍是阻塞的)

IO模型-同步非阻塞IO

相对于阻塞IO,虽然大幅提升了性能,但是它依然存在性能问题,即频繁的轮询,导致频繁的系统调用,同样会消耗大量的CPU资源

(3)IO多路复用模型

IO多路复用,系统为我们提供一类函数,可以监听多个fd操作,任何一个返回内核数据就绪,应用进程再发起系统调用获取数据,Linux中IO复用的实现方式有select、poll、epoll

select

IO模型-IO多路复用

(4)信号驱动模型

当进程发起一个IO操作,不会主动询问确认数据是否就绪,而是会向内核发送一个信号,然后进程可以去做别的事情,不会导致阻塞;当内核数据就绪时会发送一个信号通知用户进程,进程收到信号便调用系统调用读取数据。

IO模型-信号驱动

信号驱动模型,数据准备好通知进程读取数据时,数据复制仍是阻塞的,除此之外,Linux中信号队列是有限制的,超过限制就无法读取数据。

(5)异步IO模型

AIO实现IO全流程非阻塞,当进程发起一个IO操作,进程不阻塞,但也不会立即返回数据结果。内核把整个IO处理完后,会发送信号通知用户进程结果,如果IO操作成功则用户进程直接获取到数据。

IO模型-异步IO模型

四、小结

同/异步阻塞非阻塞
同步阻塞IO/IO多路复用非阻塞IO/信号驱动IO
异步xxx异步IO

阻塞IO、非阻塞IO、IO多路复用、信号驱动IO本质上都是同步的IO模型