2.2.4 NIO、多路复用、AIO

702 阅读5分钟

概念

  • 内核空间和用户空间。

    用户进程想要执行 IO 操作的话,必须通过 系统调用 来间接访问内核空间;
    当应用程序发起 I/O 调用后,会经历:1. 内核等待 I/O 设备准备好数据;2. 内核将数据从内核空间拷贝到用户空间。

  • UNIX 系统下, IO 模型一共有 5 种:  同步阻塞 I/O同步非阻塞 I/OI/O 多路复用信号驱动 I/O 和异步 I/O

  • 同步与异步(synchronous/asynchronous):

    同步是一种可靠的有序运行机制,当我们进行同步操作时,后续的任务是等待当前调用返回,才会进行下一步;
    异步则相反,其他任务不需要等待当前调用返回,通常依靠事件、回调等机制来实现任务间次序关系

  • 阻塞与非阻塞:
    在进行阻塞操作时,当前线程会处于阻塞状态,无法从事其他任务,只有当条件就绪才能继续,比如ServerSocket新连接建立完毕,或者数据读取、写入操作完成;
    非阻塞则是不管IO操作是否结束,直接返回,相应操作在后台继续处理

NIO 同步非阻塞IO(Non-blocking IO)

  • read 从开始IO读的read系统调用开始,用户线程就进入阻塞状态。一直到kernel返回结果后,用户线程才解除block的状态,重新运行起来。
    一般情况下,会为每个连接配套一条独立的线程,当在高并发的场景下,需要大量的线程。

image.png

多路复用 (IO Multiplexing)

一个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核kernel能够通知程序进行相应的IO系统调用。
IO多路复用模型的基本原理就是select/epoll系统调用,单个线程不断的轮询select/epoll系统调用所负责的成百上千的socket连接,当某个或者某些socket网络连接有数据到达了,就返回这些可以读写的连接。因此,好处也就显而易见了——通过一次select/epoll系统调用,就查询到到可以读写的一个甚至是成百上千的网络连接
目标网络连接,提前注册到select/epoll的可查询socket列表中。kernel会查询所有可查询socket列表,当任何一个socket中的数据准备好了,select/epoll就会返回。

  • select 它采用一个1024长度的数组存储数据, 所以它最多可以同时检查1024个文件描述符。
  • poll 采用链表的方式存储,避免长度限制,同时避免不必要的检查
  • epoll 采用事件通知机制,轮询没检查到事件便进行休眠,直到有事件通知它。 它在休眠的时候,cpu是闲置的。

多路复用IO的优点:

用select/epoll的优势在于,它可以同时处理成千上万个连接(connection)。与一条线程维护一个连接相比,I/O多路复用技术的最大优势是:系统不必创建线程,也不必维护这些线程,从而大大减小了系统的开销。
Java的NIO(new IO)技术,使用的就是IO多路复用模型。在linux系统上,使用的是epoll系统调用。
多路复用IO的缺点:
本质上,select/epoll系统调用,属于同步IO,也是阻塞IO。都需要在读写事件就绪后,自己负责进行读写,也就是说这个读写过程是阻塞的

AIO (Asynchronous I/O)

也叫 信号驱动 IO.
异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

(1)当用户线程调用了read系统调用,立刻就可以开始去做其它的事,用户线程不阻塞。
(2)内核(kernel)就开始了IO的第一个阶段:准备数据。当kernel一直等到数据准备好了,它就会将数据从kernel内核缓冲区,拷贝到用户缓冲区(用户内存)。
(3)kernel会给用户线程发送一个信号(signal),或者回调用户线程注册的回调接口,告诉用户线程read操作完成了。
(4)用户线程读取用户缓冲区的数据,完成后续的业务操作。

image.png

IOCP/libuv下AIO: 部分线程通过BIO或NIO获取数据,一个线程进行计算,通过线程过线程之间的通讯获取io数据。

image.png

打比如:

背景:等核酸结果 出来后订机票
同步阻塞:采样完,你蹲在医院门口等结果通知;
同步非阻塞:采样完,你每隔1min刷新一下app记录;
同步非阻塞多路复用:你每隔1min刷新一下app记录,同时观察你全家的结果,并通知他们;
epoll:采样完毕,核酸结果出来医院会通知你,这时候你可以马上预定机票了;
理想异步非阻塞:采样完毕,核酸结果出来后,触发系统自动预定机票;
libuv下AIO:提交预定机票所需信息到登记系统(观察者队列),医院(系统内核)核酸结果出来后通知 (线程池),(线程池)根据登记系统信息帮助你预定机票。

参考 www.cnblogs.com/crazymakerc…

欢迎关注我的前端自检清单,我和你一起成长