BIO、NIO、AIO

什么是IO?
IO有内存IO、网络IO和磁盘IO三种,通常我们说的IO指的是后两者
网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作

IO的模型大致有如下几种:

  • 阻塞IO(bloking IO)
  • BIO 非阻塞IO(non-blocking IO)
  • NIO 多路复用IO(multiplexingIO) MIO
  • 信号驱动式IO(signal-driven IO)
  • 异步IO(asynchronous IO)AIO
什么叫同步异步?什么叫阻塞非阻塞?

阻塞和非阻塞
阻塞和非阻塞关注的是线程在等待调用结果时的状态
我们知道线程有几种状态 running、waiting、blocked 等,其中我们看到了blocked状态,这就是阻塞状态,阻塞和非阻塞描述的就是线程在等待调用结果的时候,是不是处于这种状态

当然我们知道当线程处于阻塞的状态的时候,其是无法继续执行任何动作的,因此处于阻塞状态的线程就不可能做异步的动作

同步和异步
同步和异步关注的是通信机制,或者说关注的是结果的获取是自己负责,还是对方负责

如果是自己负责结果的获取那就是同步,如果是所有的操作都是对方负责,自己只需要等待结果的通知那就是异步

我们用打水来举例子
同学A需要一桶水,而同学B提供装一桶水的服务,于是同学A把桶交给同学B告诉他给我装一桶水,同学B这里装一桶水需要两个操作
步骤一:从水站准备一桶水
步骤二:把水装进桶里

那么:
假如同学A在同学B准备水的装水的过程中什么也不做一直在原地等待,这就属于同步阻塞

假如同学A告诉完同学B自己需要一桶水之后,在同学B准备水的过程中,一直不断的问同学B水准备好了吗,直到同学B告诉A准备好了,然后同学A开始等待同学B装水,这就属于同步非阻塞

假如同学A告诉完同学B自己需要一桶水之后,同学B告诉A知道了,然后同学A就做其他的事情去了, 一直到同学B准备好水,把水装满然后主动交给同学A,这就属于异步非阻塞

IO模型

接下来我们说的IO模型指的都是针对服务器端的

传统IO:同步阻塞式IO,也就是BIO
传统的JavaIO模型是,客户端发送一个请求,服务端接收到请求创建一个连接,然后创建一个新的线程服务读取客户端的输入数据,在客户端的输入过程中,服务端的线程处于阻塞状态,并且在接收到客户端的请求之后,客户端同样需要阻塞直到服务端完成数据处理操作返回数据
模式图如下:

在这里插入图片描述
BIO模型:
读取过程中服务器线程必须等待客户端线程输入完数据才能进行处理,这就是BIO

缺点:
首先服务端每次接收到客户端的请求都创建一个新的线程来维护连接,这会让服务器可以服务的客户端数量受限于服务器能够创建的线程数量,并且大量的线程切换会导致cpu性能下降

整个读取过程中服务器线程必须等待客户端线程输入完数据才能进行处理,导致了大量的线程处于阻塞状态,是非常严重的资源浪费

NIO模型:同步非阻塞式IO
当用户线程(服务器端的用户线程:相对于服务器的内核是用户)发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作
一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回
所以事实上,在非阻塞 IO 模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞 IO不会交出 CPU,而会一直占用 CPU

java里的NIO用到了多路复用技术
多路复用IO:

在多路复用模型中,把BIO模型中每个连接创建一个线程使用一个死循环处理数据,变成了使用一个线程一个死循环来处理多个连接数据
在这里插入图片描述
这就是多路复用IO模型中selector的作用,一条连接来了之后,直接把这条连接注册到selector上

然后,通过检查这个selector,就可以批量监测出有数据可读的连接,进而阻塞读取连接上的数据

为什么是同步?

  • 因为不能同时进行多个处理

为什么是非阻塞?

  • 因为线程可以继续运行

多路复用IO解决了两个问题:
其一是线程数量过多,多路复用IO使用一个线程读取数据使得线程数量大大降低,线程切换效率因此也大幅度提高

其二是多个线程阻塞等待客户端数据,导致的大量线程阻塞
并且NIO优化了数据传输,使用字节块来代替字节流,提升了数据传输的效率

NIO的特点是-等待数据阶段不会被阻塞,-拷贝数据阶段会被阻塞。

AIO模型:异步非阻塞IO模型(基于方法的回调)

BIO/NIO都需要在调用读写方法后,要么一直等待,要么轮询查看,直到有了结果再来执行后续代码,这就是同步
AIO是真正的异步,当进行读写操作时,直接调用API的 read 或 write 方法即可

对于读操作而言,当有流可读取时,操作系统会将可读的流传入 read 方法的缓冲区,并通知应用程序;
对于写操作而言,当操作系统将 write 方法传递的流写入完毕时,操作系统主动通知应用程序

可以看出AIO的关键在于事件的通知,也就是方法的回调,当调用者调用IO方法的时候程序可以直接继续往下执行,系统会自己完成IO操作,然后调用调用者的回调方法

同步和异步的区别
同步和异步最关键的区别在于同步必须等待(BIO)或者主动的去询问(NIO)IO是否完成,而异步(AIO)操作提交后只需等待操作系统的通知即可
总结:同步和异步的区别在于数据访问的时候进行是否阻塞,是对于服务器数据处理纬度来说的

阻塞和非阻塞只针对同步IO,永远不存在异步阻塞IO

阻塞和非阻塞的区别
阻塞和非阻塞的区别在于:应用程序的调用是否立即返回,是对于应用程序来说的
两者描述的纬度不同

大型网站一般都会使用消息中间件进行解藕、异步、削峰,生产者将消息发送给消息中间件就返回,消息中间件将消息转发到消费者进行消费,这种操作方式其实就是异步(其实就是长连接的push 推的模式:由消息中间件主动将消息推送给消费者)

上诉5种IO模型,只有异步IO方式达到了完全的非阻塞,阻塞式IO则是完全阻塞。但是常用的还是复用IO的方式,设计的好足以媲美aio,而且aio在某些情况性能不如epoll方式,和其具体实现有关。select/epoll和aio造就了两种设计模式,前者是reactor,后者就是proactor

NIO实现方式

BIO–》NIO–》多路复用NIO–》AIO ,从BIO到AIO效率是一步一步提升的,因为让调用者线程等待的时间越来越缩短了

Java的NIO采取的是多路IO复用模式
其衍生出来的模型就是Reactor模型。多路IO复用有两种方式,一种是select/poll,另一种是epoll。在windows系统上使用的是select/poll方式,在linux上使用的是epoll方式,主要是由于DefaultSelectorProvider具体选择的selector决定

多路IO复用的基本思路,阻塞发生在select上面,select管理所有注册在其上的socket请求,socket准备完全就会交由用户程序处理

数据发送接收流程:发送方发送数据->buffer->发送方channel->接收方channel->buffer->接收方接收数据

实现方式:
BIO模型下的读取或者写入函数将一直等待,而NIO模型下,读取或者写入方法会立即返回一个状态值,确定是否进入阻塞读取数据阶段,如果没有数据则不断轮询所有的连接
在AIO模型下,系统会通知删除功能应用结果

NIO网络连接读取数据的过程:

  1. 当一个网络请求过来时,都是先经由网卡接收数据,然后再把数据从网卡读入内存中,这样才完成了整个IO操作
  2. 假设网卡读写时间为5s,应用程度读写时间为1s
  3. BIO模型下每个连接的耗时为6s,处理能力为10个/分钟;
  4. 而NIO模型下,不仅减少了线程无意义等待的时间,而且程序也无需等待那些处于网卡可读状态的连接,所以每个连接耗时为1s,处理能力为60个/分钟!

这就是NIO比BIO快的根本原因
在这里插入图片描述

NIO基于事件,根据操作系统的事件来进行操作,例如:当用户请求进来的时候,操作系统会发出一个连接事件,acceptor接收器响应事件就把连接接收进来,当read事件发生的时候会分配一个线程去读取数据,当一个send事件发生的时候去读取数据
reactor是一个抽象模型,acceptor接收器是一个大管家
在这里插入图片描述
比较上一幅图中的设计,下面的这个设计使用主reactor用来专门接受请求,子reactor进行事件的轮训处理以及读写操作,而且多了一个线程池来管理线程

IO的阻塞如何实现的?
换句话说如何实现的:服务器端只有当客户端连接上的时候才会执行后面的代码ServerSocket。accept之后的代码
我们来看一下ServerSocket的关键源码,在使用ServerSocket的accept方法获取一个连接的时候,ServerSocket会调用SocketImpl的accept方法,然后调用socketAccepts()方法,并最终会调用到一个native方法:

static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;

服务器在等待客户端发送数据的时候就是阻塞在这个方法这里的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值