1.3.1同步阻塞模型
首先解释一下阻塞与非阻塞,阻塞IO,指的是需要内核IO操作彻底完成后,才返回到用户空间执行用户程序的操作指令,阻塞一词指的是用户程序的执行状态是阻塞的。可以说传统的IO操作都是阻塞的,并且在Java中,默认创建的socket都是阻塞的。
其次,解释一下同步与异步,简单来说,可以把同步和异步看成是两种发起IO请求的方式。同步IO指的是用户程序是作为主动发起IO请求的一方,系统内核是被动接受方。异步IO则反过来,系统内核是主动发起IO请求的一方,用户空间则是被动接收方。
所谓同步阻塞IO,是指用户程序作为主动发起IO请求的一方,需要等到内核IO操作彻底完成后,才可以返回执行用户空间的操作指令。IO操作过程中,发起IO请求的用户进程处于阻塞状态。
同步阻塞模型的处理流程
用户程序主动发起IO请求,进入阻塞状态;
操作系统收到请求,开始准备数据到内核缓冲区,这个时候内核就要等待;
内核一直等待数据到达后,内数据从内核缓冲区中复制到用户空间的进程缓冲区,然后内核返回结果;
直到内核返回后,用户程序才会解除阻塞状态,重新运行起来。
阻塞IO的特点:在内核进行IO执行的两个阶段,发起IO请求的用户进程被阻塞了(内核等待数据到达和复制数据到进程缓冲区)。
阻塞IO的优点:应用的程序开发非常简单:在阻塞等待数据期间,用户线程挂起,几乎不会浪费CPU资源。
阻塞IO的缺点:一般情况下,会为每个连接配备一个独立的线程,一个线程维护一个连接的IO操作。在并发量小的情况下,这样做没有什么问题。但是,在高并发场景下,需要大量的线程维护大量的网络连接,内存、线程的切换消耗会非常巨大。在高并发场景下,阻塞IO性能是很低的,基本上是不可用的。
1.3.2同步非阻塞模型
所谓同步非阻塞模型,指的是用户程序主动发起,不需要等待内核的IO操作彻底完成,就能立即返回到用户空间的IO操作,IO操作过程中,发起IO请求的用户进程处于非阻塞状态。
同步非阻塞IO的处理流程:
(1)在内核缓冲区中没有数据的时候,系统调用会立即返回,返回一个调用失败的信息。
(2)在内核缓冲区中有数据的时候,在数据的复制过程是阻塞的,直到数据从内核缓冲区完整的复制到进程缓冲区中。复制完成后,系统调用返回成功,用户进程解除阻塞状态。
发起一个非阻塞socket的read系统调用,流程如下:
(1)在内核缓冲区数据没有准备好的阶段,用户发起IO请求时,立即返回,所以,为了读取到最终的数据,用户进程要不断的发起系统调用。
(2)当内核缓冲区中的数据到达后,用户进程进入阻塞状态,内核将数据从内核缓冲区复制到进程缓冲区中。
(3)复制完成后,系统调用返回成功,用户空间解除阻塞状态,重新运行起来。
同步非阻塞IO的特点:应用程序的线程需要不断地进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就一直轮询,直到数据到达。
同步非阻塞IO的优点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。
同步非阻塞IO的缺点:用户需要不断的发起IO系统调用来轮询数据是否准备好,这将占用大量的CPU时间,效率低下。
1.3.3IO多路复用模型
为了提高性能,操作系统引入了一类新的系统调用,专门用于查询IO文件描述符的就绪状态。在Linux系统中,新的系统调用为select/epoll系统调用。通过该系统调用,一个用户进程可以监视多个文件描述符,一旦某个文件描述符就绪,内核能够将该文件描述符的就绪状态返回给用户进程,用户空间可以根据文件描述符的就绪状态,进行响应的IO系统调用。
发起一个多路复用IO的read系统调用,流程如下:
(1)选择器注册。在这种模式中,首先,将需要read操作的目标文件描述符,提前注册到Linux的select/epoll选择器中,在Java中所对应的选择器是Selector类。然后,才可以开启整个IO多路复用模型的轮询流程。
(2)就绪状态的轮询。通过选择器的查询方法,查询所有提前注册过的目标文件列表。当任何一个注册过的socket中的数据准备好或者就绪了,就是内核缓冲区有数据了,内核就将该socket加入到就绪的列表中,并且返回就绪事件。
(3)用户线程获得了就绪状态的列表后,根据其中的socket连接,发起read系统调用,用户线程阻塞。内核开始复制数据,将数据从内核缓冲区复制到进程缓冲区。
IO多路复用模型的特点:IO多路复用模型的IO涉及两种系统调用:一种是IO操作的系统调用,另一种是select/epoll就绪状态系统调用。IO多路复用建立在操作系统的基础设施之上,即操作系统的内核必须能够提供多路复用的系统调用select/epoll。
IO多路复用模型的优点:一个选择器查询线程,可以同时处理成百上千的socket连接,所以,用户程序不必建立大量的线程,也不必维护这些线程,从而大大减少了系统的开销。这是一个线程维护一个连接的阻塞IO模式相比,使用多路复用IO模型的最大优势。
IO多路复用模型的缺点:本质上,select/epoll系统是阻塞式的,属于同步IO。都需要在读写事件就绪后,由系统调用本身负责进行读写,也就是说这个读写过程是阻塞的,如何彻底地解除线程的阻塞,就必须使用异步IO模型。