驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
NIO-概念理解
/  

NIO-概念理解

开篇

我们一直都在说传统的 IO属于阻塞 IO,而 NIO属于非阻塞的 IO.

我一直在理解 阻塞 IO 和 非阻塞 IO 的区别。

看了这么多文章后,今天算是小有所获,可以用形象的语言来表达他们的区别了。

需求背景

我们利用一个需求来进行解释:服务端需要接收多个客户端传输过来的信息,该流程只包含接收部分,至于接收到的数据是通过线程池进行处理还是怎么处理,不属于本章讨论范畴,我们只讨论几种不同的IO的接收流程。

阻塞 IO:BIO

传统的IOBIO 也称为同步阻塞 IO。阻塞是体现在哪里了?

首先给个结论:它会从头阻塞到尾!

我们通过下图进行理解:

阻塞IO

一个应用读取到数据,其实是经过了2个流程。

  1. 数据先是通过网络填充满系统内核
  2. 然后从系统内核读取到应用程序(用户空间)

上述2个流程很重要,请用心背住并多加理解。

BIO在每一次IO读取上,会在第一个流程开始到第二个流程结束这个全过程中阻塞

结合具体的业务来讲:客户端同服务端每建立一个连接进行数据传输时,服务端就需要1个线程等待上述进行1和2完成后,才能进行后续收集到的数据的处理任务。

这个过程意味着,服务端需要同N个客户端进行通信,那么在服务端就需要N个线程进行监听。

非阻塞 IO:NIO

NIO 也就是 同步非阻塞 IO,它优化了传统 IO 在上述流程中的第1步。

这里的非阻塞指的就是:在第一个流程中,判定系统内核的数据是否可读上,是非阻塞的,是通过不停轮询进行判定的。

具体而言如下图所示:

非阻塞IO

异步IO 在第一个流程中,线程会不段的轮询去获取系统内核的数据是否就位这个状态,如果就位了,才能将数据从系统内核拷贝到用户空间。在第一个流程中,系统是没有被阻塞的,但是却是在不停的进行轮询判定。

这个地方其实我也是有疑问的:

非阻塞IO对于阻塞IO而言,非阻塞IO在第一个流程确实是阻塞,但是其却是只能通过不停轮询判定数据是否可读的状态。这样做,性能上有何提升?

望有高手能够解答下这个疑惑!

IO多路复用

IO多路复用是在NIO基础的改进,Netty就是基于IO多路复用进行数据接收的。

IO多路复用

首先IO多路在不同系统的不同模式下实现是由细微差异的,不过大体的流程一致。

在第一个阶段上:

  • 每一个连接都会注册到系统的 系统内核上。
  • 系统通过某种手段(select\poll\epoll) 判定当前数据是否可读,当可读的时候通过callback事件回调的方式,进行后续数据处理。
  1. select和poll模型支持的fd有限,且对于fd的扫描是顺序扫描,所以高并发下性能不好。
  2. Linux下的epoll模型支持更多的fd基于活跃扫描并回调的方式进行处理,所以高并发下性能更好。

还有一点需要指出:通过IO多路复用,可以1个线程支持多个连接,这个是上述IO模型不具备的。

异步IO:AIO

异步IO异步非阻塞IO,性能更强大了,全程都是基于callback的。

如下图所示:

异步IO

举例说明

我们通过一个现实的例子来举例:我们去银行办理业务,需要先填写业务表单,然后才能进行后续的业务。

传统的 IO就是:你走到柜台后,柜台小姐姐盯着你填写业务表单,后续给你办理业务。在填写表单到后续业务处理的过程,柜台小姐姐会一直为你服务。这个过程中你填写业务表达的过程的时候,柜台小姐姐就只是盯着你而已,并没有做什么工作,存在资源浪费。

多路复用就是:你先到银行大厅填表,当你填写完成后你告诉大厅分流的小姐姐我填写完成了,然后由她给你安排一个操作柜台进行后续业务处理。

说实话,这篇文章,修改了几次,随着个人理解加深,很多地方感觉还是不够,希望大家多多指点。

参考地址

https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Socket.md

https://blog.csdn.net/woaixiaopangniu521/article/details/70279143

骐骥一跃,不能十步。驽马十驾,功在不舍。