初识IO模型 — IO|BIO|NIO|AIO|Select|Epoll

2 篇文章 0 订阅
1 篇文章 0 订阅
本文详细介绍了计算机的IO模型,包括阻塞IO、非阻塞IO、IO多路复用(select、poll、epoll)、信号驱动IO以及异步IO(AIO)。阐述了各种模型的工作原理、优缺点,并通过对比分析强调了异步IO的高效特性。同时,总结了阻塞、非阻塞、同步、异步IO的概念差异。
摘要由CSDN通过智能技术生成

IO模型

1 到底什么是IO?

计算机角度的IO

比较直观的例子是 计算机的输入输出

其中计算机组成原理中的冯-诺伊曼结构,就是将计算机分成5个部分:运算器、控制器、存储器、输入设备、输出设备。

在这里插入图片描述

涉及计算机核心与其他设备间数据迁移的过程,就是IO。

如磁盘IO,就是将磁盘读取数据到内存,这算一次输入,对应的,从内存中的数据写入到磁盘,就是一次输出。这就是IO的本质。

操作系统的IO

我们要将内存中的数据写入到磁盘中,主体会是什么呢?

主体可能是一个Java程序,假设网络传来的二进制流,一个Java进程可以把它写入磁盘。

操作系统负责计算机的资源管理和进程调度

我们运行的应用程序,其实需要操作系统,才能做的一些特殊操作,如磁盘文件读写、内存的读写等等。

因为这些危险的操作不可以由应用程序乱来,只能交给底层操作系统来操作,我们直接调用操作系统开发的API就行了。

  • 什么是用户空间?什么是内核空间?
  • 以32位操作系统为例,它为每一个进程都分配了4G(2的32次方)的内存空间。这4G可访问的内存空间分为二部分,一部分是用户空间,一部分是内核空间。内核空间是操作系统内核访问的区域,是受保护的内存空间,而用户空间是用户应用程序访问的内存区域。

我们的应用程序是跑在用户空间中的,不存在实质的IO过程,真正的IO是在操作系统内核执行的

即应用程序IO操作分为:IO调用和IO执行。

2 操作系统中的一次IO过程

应用程序发起的一次IO操作包含两个阶段:

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

而内核完成一次IO执行操作还包括三个过程:

  • 准备数据阶段:内核等待I/O设备准备好已经写入内核缓冲区中的数据
  • 拷贝数据阶段:将数据从内核缓冲区拷贝到用户进程缓冲区

在这里插入图片描述


接下来是经典的5中IO模型梳理


3 阻塞IO模型

假设应用程序的进程发起IO调用,但是如果内核还没有准备好的话,那么应用程序进程就会一直 阻塞等待 。一直等到内核数据准备好了,从内核拷贝到用户空间,才返回成功提示,应用程序才会解除 Block 状态,这次IO操作就是 阻塞IO 。

在这里插入图片描述

阻塞IO的经典应用是 阻塞Socket、Java BIO。

阻塞IO的缺点就是:如果内核数据一直没准备好,那么用户进程就会一直阻塞交出CPU,浪费性能,可以使用非阻塞IO优化。

4 非阻塞IO模型

如果内核数据没有准备好,那么可以先返回错误信息给用户进程,让它需要等待,而是通过轮询的方式再来请求,这就是非阻塞IO。

在这里插入图片描述

非阻塞IO流程:

  • 应用程序向操作系统内核,发起 recvfrom 读取数据
  • 此时OS内核还没有准备好数据,就会立即发送一个EWOULDBLOCK错误码
  • 应用程序进程轮询调用,就会继续向内核发出recvfrom读取数据
  • 此时内核的数据已经准备好了,就从内核缓冲区的数据拷贝到用户空间。
  • 完成调用,返回成功提示。

缺点:看似是非阻塞了,其实本质上仍然是阻塞的,会一直占用CPU,浪费CPU资源

5 IO多路复用模型

既然 NIO 无效的轮询会导致CPU资源消耗,我们等到内核数据准备好了,主动通知应用进程再去系统调用,那不就好了嘛?

此时,我们需要了解一下,文件描述符fd(File Descriptor),形式上是一个非负整数,当应用程序打开一个现有文件或者创建一个新的文件,内核就会向进程返回一个文件描述符。

多路复用 IO 模式,通过一个线程就可以管理多个 socket,只有当 socket 真正有读写事件发生才会占用资源来进行实际的读写操作。

IO复用模型的核心思路:系统会给我们一类函数(select、poll、epoll函数),它们可以监控多个 fd 操作,任何一个返回内核数据就绪,应用程序再发起recvfrom系统调用

IO多路复用之select

应用进程通过调用select函数,可以同时监控多个fd,在select函数监控的fd中,只要有任何一个数据状态准备就绪了,select函数就会返回一个可读状态,这时应用进程再发起recvfrom请求来读取数据。

在这里插入图片描述

NIO中,需要N次轮询系统调用,然而借助了select的IO多路复用模型,只需要发起一次系统调用就可以了,大大优化了性能

另外多路复用 IO 为何比非阻塞 IO 模型的效率高是因为在非阻塞 IO 中,不断地询问 socket 状态时通过用户线程去进行的,

而在多路复用 IO 中,轮询每个 socket 状态是内核在进行的,这个效率要比用户线程要高的多。

但是,select还是有几个缺点:

  • 监听IO的最大连接数有限,在Linux系统上一般为1024。

  • select函数返回后,是通过遍历fdset,找到就绪的描述符fd。

    (仅知道有I/O事件发生,却不知是哪个socket,因此需要遍历所有的socket)

  • 一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。

因为select有最大连接数的限制,所以之后提出了poll。

与select相比,poll解决了 连接数限制的问题。但是呢,select和poll一样都是要去遍历socket的fd来获取就绪的socket。

如果同时连接大量的客户端,在一时刻可能只有极少数的处于就绪状态,但伴随着监视的fd数量增长,效率就会大大下降。

之后,epoll 就诞生了。

6 IO多路复用之epoll

为了解决select/poll存在的问题,就出现了epoll,它是采用事件驱动来实现的。

在这里插入图片描述

epoll先通过epoll_ctl()来注册一个fd,一旦基于fd就绪时,内核就会采用回调机制,迅速激活这个fd,当进程调用epoll_wait()时便得到通知。这里去掉了遍历fd的操作,而是监听事件回调机制,这就是epoll的亮点

select、poll、epoll的区别

selectpollepoll
底层数据结构数组链表红黑树和双链表
获取就绪的fd遍历遍历事件回调
事件复杂度O(n)O(n)O(1)
最大连接数1024无限制无限制
fd数据拷贝每次调用select,需要将fd数据从用户空间拷贝到内核空间每次调用poll,需要将fd数据从用户空间拷贝到内核空间使用内存映射(mmap),不需要从用户空间频繁拷贝fd数据到内核空间

epoll明显优化了IO的执行效率,但在进程调用epoll_wait()时,仍然可能被阻塞

因为我们可以假设进程无需时不时去询问数据是否准备就绪,等进程发出请求后,内核数据准备好了通知进程就行了,就诞生了信号驱动IO模型。

7 IO模型之信号驱动模型

信号驱动IO就不再主动询问内核数据是否准备就绪,而是向内核发出一个信号(调用 sigaction 时候建立一个 SIGIO 的信号),然后应用用户进程可以去做别的事,不用阻塞。

当内核数据就绪时,在通过SIGIO信号通知应用进程,数据准备好的可读状态。当应用用户进程收到信号之后,立即调用recvfrom,去读取数据。

在这里插入图片描述

信号驱动IO模型,在应用程序发出信号时,是立即返回的,不会阻塞用户进程的。

看似其中已经是异步操作了,但仔细一看的话,可以看出,数据复制到用户缓冲区的期间,应用进程还是阻塞的。

回头来看,不管是BIO,还是NIO,还是信号驱动,在数据从内核复制到应用缓冲区的时候,都是阻塞的

因此就引出来真正的异步大BossIO——AIO!

8 IO模型终结者之异步IO(AIO)

前面提到的BIO、NIO和信号驱动,在数据从内核到用户缓冲的过程都是阻塞的,因此都不算是真正的异步。

AIO实现了IO全流程的非阻塞,应用程序发出系统调用后,立即返回不是处理的结果,而是提交成功的结果。

等内核数据准备好,将数据拷贝到用户进程缓冲区,发送信号后通知用户进程IO操作执行完毕,用户就可以直接使用数据了。

在这里插入图片描述

异步IO的优化思路很简单,只需要向内核发送一次请求,就可以完成数据状态询问和数据拷贝的所有操作,并且不用阻塞等待结果。日常开发中,有类似思想的业务场景:

比如发起一笔批量转账,但是批量转账处理比较耗时,这时候后端可以先告知前端转账提交成功,等到结果处理完,再通知前端结果即可。

阻塞、非阻塞、同步、异步IO汇总

在这里插入图片描述

IO模型
阻塞I/O模型同步阻塞
非阻塞I/O模型同步非阻塞
I/O多路复用模型同步阻塞
信号驱动I/O模型同步非阻塞
异步IO(AIO)模型异步非阻塞
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值