基本概念
基本概念 | |
---|---|
阻塞IO | 指的是需要内核IO操作彻底完成 后,才返回到用户空间执行用户的操作。阻塞指的是用户空间程序的执行状态。传统的IO模型都是同步阻塞IO。在Java中,默认创建的socket都是阻塞的。 简单来说:阻塞是指用户空间(调用线程)一直在等待,而不能干别的事情; |
非阻塞IO | 指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回 用户空间执行用户的操作,即处于非阻塞的状态,与此同时内核会立即返回给用户一个 状态值 。简单来说:非阻塞是指用户空间(调用线程)拿到内核返回的状态值就返回自己的空间,IO操作可以干就干,不可以干,就去干别的事情。 |
同步IO | 是一种用户空间与内核空间的IO发起方式。同步IO是指用户空间的线程是主动发起 IO请求的一方,内核空间是被动接受方。 |
异步IO | 则反过来,是指系统内核是主动发起 IO请求的一方,用户空间的线程是被动接受方。异步IO,指的是用户空间与内核空间的调用方式反过来。用户空间的线程变成被动接受者,而内核空间成了主动调用者。 这有点类似于Java中比较典型的 回调模式 ,用户空间的线程向内核空间注册了各种IO事件的回调函数,由内核去主动调用。 |
同步阻塞IO(Blocking IO)
在阻塞式IO模型中,Java应用程序从IO系统调用开始,直到系统调用返回,在这段时间内,Java进程是阻塞的。返回成功后,应用进程开始处理用户空间的缓存区数据。同步阻塞IO的具体流程,如下图所示。 |
---|
举个例子,在Java中发起一个socket的read读操作的系统调用,流程大致如下: |
---|
(1)从Java启动IO读的read系统调用开始,用户线程就进入阻塞 状态。 |
(2)当系统内核收到read系统调用,就开始准备数据 。一开始,数据可能还没有到达内核缓冲区(例如,还没有收到一个完整的socket数据包),这个时候内核就要等待。 |
(3)内核一直等到完整的数据到达,就会将数据从内核缓冲区复制 到用户缓冲区(用户空间的内存),然后内核返回 结果(例如返回复制到用户缓冲区中的字节数)。 |
(4)直到内核返回后,用户线程才会解除阻塞 的状态,重新运行起来。 |
总之,阻塞IO的特点是:在内核进行IO执行的两个阶段,用户线程都被阻塞了。 |
阻塞IO的优点是:应用的程序开发非常简单 ;在阻塞等待数据期间,用户线程挂起。在阻塞期间,用户线程基本不会占用CPU 资源。 |
阻塞IO的缺点是:一般情况下,会为每个连接配备一个独立 的线程;反过来说,就是一个线程维护一个连接的IO操作。在并发量小的情况下,这样做没有什么问题。但是,当在高并发的应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销 会非常巨大。因此,基本上阻塞IO模型在高并发应用场景下是不可用的。 |
同步非阻塞NIO(None Blocking IO))
AIO的基本流程是:用户线程通过系统调用,向内核注册某个IO操作。内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后续的业务操作。 |
---|
在异步IO模型中,在整个内核的数据处理过程中,包括内核将数据从网络物理设备 (网卡)读取到内核缓冲区 、将内核缓冲区的数据复制到用户缓冲区 ,用户程序都不需要阻塞。异步IO模型的流程,如下图所示。 |
举个例子。发起一个异步IO的read读操作的系统调用,流程如下: |
---|
(1)当用户线程发起了read系统调用,立刻就可以开始去做其他的事,用户线程不阻塞。 |
(2)内核就开始了IO的第一个阶段:准备数据。等到数据准备好了,内核就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存)。 |
(3)内核会给用户线程发送一个信号(Signal),或者回调用户线程注册的回调接口,告诉用户线程read操作完成了。 |
(4)用户线程读取用户缓冲区的数据,完成后续的业务操作。 |
异步IO模型的特点:在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接收内核的IO操作完成的事件,或者用户线程需要注册一个IO操作完成的回调函数。正因为如此,异步IO有的时候也被称为信号驱动IO。 |
异步IO异步模型的缺点:应用程序仅需要进行事件的注册与接收,其余的工作都留给了操作系统,也就是说,需要底层内核提供支持。 |
理论上来说,异步IO是真正的异步输入输出,它的吞吐量高于IO多路复用模型的吞吐量。 |
就目前而言,Windows系统下通过IOCP实现了真正的异步IO。而在Linux系统下,异步IO模型在2.6版本才引入,目前并不完善,其底层实现仍使用epoll,与IO多路复用相同,因此在性能上没有明显的优势。 |
大多数的高并发服务器端的程序,一般都是基于Linux系统的。因而,目前这类高并发网络应用程序的开发,大多采用IO多路复用模型。 |
大名鼎鼎的Netty框架,使用的就是IO多路复用模型,而不是异步IO模型。 |
IO多路复用模型(IO Multiplexing)
异步IO模型(Asynchronous IO)
-----------------------------------------------------------------------------读书笔记摘自书名:Netty、Redis、Zookeeper高并发实战 作者:尼恩