java --- BIO NIO AIO

概述

      本文将会介绍 unix 系统中 IO 的 5 种模式,在后续的文章后会介绍 reactor 和 Proactor 两种IO模式。

异步和阻塞

       我们先来大概了解了一下异步和阻塞的问题。 可以查看一下两个链接 :

https://www.zhihu.com/question/19732473/answer/20851256

https://www.zhihu.com/question/19732473/answer/14413599

阻塞非阻塞: 请求不能立即得到应答,需要等待,那就是阻塞;否则可以理解为非阻塞。

同步异步: 某业务需要甲乙甚至多方合作的时候,

  1. 总是按照“甲方请求一次,乙方应答一次”这样的有序序列处理业务,只有当“一次请求一次应答”的过程结束才可以发生下一次的“一次请求一次应答”,那么就说他们采用的是同步。(同步IO中对同一个描述符的操作必须是有序的
  2. 如果甲方只要有需要,就会发送请求,不管上次请求有没有得到乙方应答。而乙方只要甲方有请求就会接受,不是等这次请求处理完毕再接受甲方新请求。这样请求应答分开的序列,就可以认为是异步。异步情况下,请求和应答不需要一致进行,可能甲方后请求的业务,却先得到乙方的应答。同步是线性的,而异步可以认为是并发的。(异步IO中,异步IO可以允许多方同时对同一个描述符发送IO请求,或者一次发多个请求,当然有机制保证如何区分这些请求,

作者:Shihui wang
链接:https://www.zhihu.com/question/19732473/answer/14413599

       可以这样理解 : 同步异步关注的是协作方式,而阻塞和非阻塞则是遇到IO操作时,请求者当时的状态。

5种 IO 模式       

        UNIX 5种IO 模式,分别是

  • blocking IO   阻塞IO
  • non-blocking IO  非阻塞IO 
  • io multiplexing  多路复用IO
  • asynchronous IO  异步IO
     

       由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model。了解4种模式之前我们需要注意这些知识点。

  IO发生时涉及的对象和步骤。

       对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段:
1.  等待数据准备 (Waiting for the data to be ready)
2.  将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

线程数量

       同时我们还需要知道一点,对于请求,是不是创建越多的线程就越好呢?创建的线程应该和底层机器可以承受的线程数量有关,具体的可以看这篇文章,多个请求对应太多的线程有可能会导致太多的内存开销和时间分片,多个线程会导致CPU 切换线程带来的开销,我们学习计算机操作系统知道当切换线程时需要重新将之前线程执行的信息重新加载到主存中,但是有可能由于缓冲机制(例如LRU)将会淘汰掉某些信息,信息的加载将会带来时间开销。

     

blocking IO

       阻塞 IO ,可以用下面的图来表示 :

blockingIO

       可以看到 process 进程一直阻塞在调用 recvfrom 之后,一直到内核返回 ok .

non-blocking IO 

       从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
       所以,用户进程其实是需要不断的主动询问kernel数据好了没有
non-blocking

IO multiplexing

       多路复用 IO , 它将会首先调用select 函数,当数据没准备好,进程依旧会被阻塞,当内核数据准备好,它会通知一下用户进程,用户进程调用 recvfrom 函数,进入第二次阻塞,等内核将数据成功拷贝到用户进程的时候,用户进程成功返回。过程如下 :

mult

       可以知道,多路复用会比之前的模式多了一次函数调用,上面我们也可以使用 多线程+ 阻塞IO 的方式来实现,那么多路复用这种方式又在哪里呢?使用select可以处理更多的connection, select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。实际中我们会使用 non-blocking  + 多路复用,这样轮询是否有事件到来的请求就交给 select 来完成就可以了。

Asynchronous I/O

        用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

asynose

总结

       这篇文章,我们知道了阻塞与非阻塞,异步同步之间的区别,了解了5中 IO 模式,在后续的文章我们会深入Reator 模式和java NIO实现。

参考资料

猜你喜欢

转载自www.cnblogs.com/Benjious/p/10982525.html