BIO,NIO,AIO的理解
  Op9yysgqYUmV 2023年11月02日 43 0


前面我们已经简单了解了IO的一些概念,接下来我们再详细学习下相关概念在高性能的IO体系设计中,我们首先要清楚如下几个名词概念:

同步:执行一个操作之后,进程触发IO操作并等待(也就是我们说的阻塞)或者轮询的去查看IO操作(也就是我们说的非阻塞)是否完成,等待结果,然后才继续执行后续的操作。

异步:执行一个操作后,可以去执行其他的操作,然后等待通知再回来执行刚才没执行完的操作。

阻塞:进程给CPU传达一个任务之后,一直等待CPU处理完成,然后才执行后面的操作。

非阻塞:进程给CPU传达任我后,继续处理后续的操作,隔断时间再来询问之前的操作是否完成。这样的过程其实也叫轮询。

同步异步,阻塞非阻塞区别联系

同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知(异步的特点就是通知,使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS)。

同步有阻塞和非阻塞之分,异步没有,它一定是非阻塞的。

而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,仅仅是系统调用函数的实现方式而已,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。 

可以总结一句简短的话,同步和异步是目的,阻塞和非阻塞是实现方式。阻塞、非阻塞、多路IO复用,都是同步IO,异步必定是非阻塞的,所以不存在异步阻塞和异步非阻塞的说法。真正的异步IO需要CPU的深度参与。

所以,IO操作可以分为3类:同步阻塞(即早期的IO操作)、同步非阻塞(NIO)、异步(AIO)。 

同步阻塞 IO(JAVA BIO)

在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行,JAVA传统的IO模型属于此种方式。 服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。 

同步非阻塞IO(Java NIO)

在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,目前JAVA的NIO就属于同步非阻塞IO。 服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费 。

异步非阻塞IO(Java AIO)

NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步的套接字通道是真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。它是基于Proactor模型的,他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。

在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。   

BIO、NIO、AIO适用场景分析:

    BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。 

    NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。 

    AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。 

搞清楚了以上概念以后,我们再回过头来看看,Reactor模式和Proactor模式。  

(其实阻塞与非阻塞都可以理解为同步范畴下才有的概念,对于异步,就不会再区分阻塞非阻塞。对于用户进程,接到异步通知后,就直接操作进程用户态空间里的数据好了。)  

首先来看看Reactor模式,Reactor模式应用于同步I/O的场景。我们分别以读操作和写操作为例来看看Reactor中的具体步骤:  

读取操作:  

1. 应用程序注册读就绪事件和相关联的事件处理器  

2. 事件分离器等待事件的发生   

3. 当发生读就绪事件的时候,事件分离器调用第一步注册的事件处理器    

4. 事件处理器首先执行实际的读取操作,然后根据读取到的内容进行进一步的处理  

写入操作类似于读取操作,只不过第一步注册的是写就绪事件。  

   

下面我们来看看Proactor模式中读取操作和写入操作的过程:  

读取操作:  

1. 应用程序初始化一个异步读取操作,然后注册相应的事件处理器,此时事件处理器不关注读取就绪事件,而是关注读取完成事件,这是区别于Reactor的关键。  

2. 事件分离器等待读取操作完成事件   

3. 在事件分离器等待读取操作完成的时候,操作系统调用内核线程完成读取操作(异步IO都是操作系统负责将数据读写到应用传递进来的缓冲区供应用程序操作,操作系统扮演了重要角色),并将读取的内容放入用户传递过来的缓存区中。这也是区别于Reactor的一点,Proactor中,应用程序需要传递缓存区。   

4. 事件分离器捕获到读取完成事件后,激活应用程序注册的事件处理器,事件处理器直接从缓存区读取数据,而不需要进行实际的读取操作。  

Proactor中写入操作和读取操作,只不过感兴趣的事件是写入完成事件。  

  

从上面可以看出,Reactor和Proactor模式的主要区别就是真正的读取和写入操作是有谁来完成的,Reactor中需要应用程序自己读取或者写入数据,而Proactor模式中,应用程序不需要进行实际的读写过程,它只需要从缓存区读取或者写入即可,操作系统会读取缓存区或者写入缓存区到真正的IO设备.  

   

如果你想吃一份宫保鸡丁盖饭: 

同步阻塞:你到饭馆点餐,然后在那等着,还要一边喊:好了没啊! 

同步非阻塞:在饭馆点完餐,就去遛狗了。不过溜一会儿,就回饭馆喊一声:好了没啊! 

异步阻塞:在饭馆点完餐,就去遛狗了。遛狗的时候,接到饭馆电话,说饭做好了,让您亲自去拿。 

异步非阻塞:饭馆打电话说,我们知道您的位置,一会给你送过来,安心遛狗就可以了。 

 

一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作。 

同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO。 

阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。 

BIO,NIO,AIO的理解_Java

参考:

http://qindongliang.iteye.com/blog/2018539


https://www.jianshu.com/p/331ee864bda9

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

上一篇: 微服务架构缓存 下一篇: Go语言数组
  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  xaeiTka4h8LY   2024年05月17日   54   0   0 数据库JavaSQL
  2iBE5Ikkruz5   2023年12月12日   93   0   0 JavaJavaredisredis
Op9yysgqYUmV