我们一直都在说传统的 IO属于阻塞 IO,而 NIO
属于非阻塞的 IO.
我一直在理解 阻塞 IO 和 非阻塞 IO 的区别。
看了这么多文章后,今天算是小有所获,可以用形象的语言来表达他们的区别了。
我们利用一个需求来进行解释:服务端需要接收多个客户端传输过来的信息,该流程只包含接收部分,至于接收到的数据是通过线程池进行处理还是怎么处理,不属于本章讨论范畴,我们只讨论几种不同的IO的接收流程。
传统的IO
是BIO
也称为同步阻塞 IO
。阻塞是体现在哪里了?
首先给个结论:它会从头阻塞到尾!
我们通过下图进行理解:
一个应用读取到数据,其实是经过了2个流程。
网络
填充满系统内核
系统内核
读取到应用程序(用户空间)
上述2个流程很重要,请用心背住并多加理解。
BIO
在每一次IO
读取上,会在第一个流程开始到第二个流程结束这个全过程中阻塞
。
结合具体的业务来讲:客户端同服务端每建立一个连接进行数据传输时,服务端就需要1个线程等待上述进行1和2完成后,才能进行后续收集到的数据的处理任务。
这个过程意味着,服务端需要同N个客户端进行通信,那么在服务端就需要N个线程进行监听。
NIO 也就是 同步非阻塞 IO
,它优化了传统 IO 在上述流程中的第1步。
这里的非阻塞指的就是:在第一个流程中,判定系统内核的数据是否可读上,是非阻塞的,是通过不停轮询进行判定的。
具体而言如下图所示:
异步IO 在第一个流程中,线程会不段的轮询去获取系统内核的数据是否就位这个状态,如果就位了,才能将数据从系统内核拷贝到用户空间。在第一个流程中,系统是没有被阻塞的,但是却是在不停的进行轮询判定。
这个地方其实我也是有疑问的:
非阻塞IO
对于阻塞IO
而言,非阻塞IO
在第一个流程确实是阻塞,但是其却是只能通过不停轮询判定数据是否可读的状态。这样做,性能上有何提升?望有高手能够解答下这个疑惑!
IO多路复用
是在NIO
基础的改进,Netty就是基于IO多路复用
进行数据接收的。
首先IO多路
在不同系统的不同模式下实现是由细微差异的,不过大体的流程一致。
在第一个阶段上:
系统内核
上。(select\poll\epoll)
判定当前数据是否可读,当可读的时候通过callback
事件回调的方式,进行后续数据处理。
- select和poll模型支持的
fd
有限,且对于fd
的扫描是顺序扫描
,所以高并发下性能不好。- Linux下的
epoll
模型支持更多的fd
和基于活跃扫描并回调
的方式进行处理,所以高并发下性能更好。
还有一点需要指出:通过IO多路复用,可以1个线程支持多个连接,这个是上述IO模型不具备的。
异步IO
是异步非阻塞IO
,性能更强大了,全程都是基于callback
的。
如下图所示:
我们通过一个现实的例子来举例:我们去银行办理业务,需要先填写业务表单,然后才能进行后续的业务。
传统的 IO就是:你走到柜台后,柜台小姐姐盯着你填写业务表单,后续给你办理业务。在填写表单到后续业务处理的过程,柜台小姐姐会一直为你服务。这个过程中你填写业务表达的过程的时候,柜台小姐姐就只是盯着你而已,并没有做什么工作,存在资源浪费。
多路复用就是:你先到银行大厅填表,当你填写完成后你告诉大厅分流的小姐姐我填写完成了,然后由她给你安排一个操作柜台进行后续业务处理。
说实话,这篇文章,修改了几次,随着个人理解加深,很多地方感觉还是不够,希望大家多多指点。
https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Socket.md
https://blog.csdn.net/woaixiaopangniu521/article/details/70279143