了解 “BIO、NIO、AIO”

一、阻塞?同步?

可能大家平常会经常听到这两个名词,但是没花太多心思详细了解,今天就来揭开这层面纱。

一次IO操作,以read方法举例,会经历两个阶段:
(1)等待数据准备(Waitingfor the data to be ready)
是否阻塞指的就是这一个阶段。

(2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
是否同步指的就是这一个阶段。

二、BIO

即blocking IO,阻塞式IO,大家最为熟悉的IO流,经常用于操作网络请求,文件读写之类。按读取类型可分为两大类:字符流,字节流。详情图如下:

IO流详情图

附上普通I/O(BIO)的读流程图示:

BIO阻塞同步图

当左边的应用进程发出了“system call”命令后,kernel首先进入第一阶段“wait for data”,然后再进入第二阶段“copying the data”,最后“return OK”返回到用户进程中,即BIO在两个阶段都是阻塞block的,阻塞并同步。

三、NIO

即non-blocking IO,也叫做new IO,因为是NIO是JDK 1.4的java.nio.*包中引入的新I/O库,目的是提高速度,也是对之前的BIO一个补充完善。

NIO的三个重点,重中之重的是:

1. channel(通道)

连接data数据与buffer缓存区的桥梁。

  • 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
  • 通道可以异步地读写。
  • 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

2. Buffer(缓冲区)

用于和NIO通道进行交互。如图所示,数据是从通道读入缓冲区,从缓冲区写入到通道中的。

buffer

3. Selector(选择器)

是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件,如此一个单独的线程可以管理多个channel,从而管理多个连接。

selector

由于selector的原因,可以将NIO简单区分为两种:普通的NIO,和多路复用的NIO(加入了selector管理)。通过下面两张IO操作图示简单说明下两者区别:

NIO非阻塞同步图

很明显的可以观测到NIO在IO操作的准备数据阶段时有一个轮询操作,会不停地发出“system call”到kernel轮询数据是否准备好,没准备好,应用进程可以处理其他事,准备好了之后在发出一个“system call”到kernel进行第二个阶段复制数据,这个过程是blocking的,所以NIO的特点就是在IO执行的第一阶段不会阻塞,但是在第二阶段将数据从内核拷贝到进程这个真是的IO操作还是会阻塞

NIO多路复用图

多路复用的NIO则是上述的普通NIO的补充,在并发量过大的情况下,不可能每个线程都要轮询自己的IO状态,这时就可以使用selector管理所有的IO通道channel,之用开启一个线程,便可解决成千上万的高并发问题(。◕ˇ∀ˇ◕)。

四、AIO

NIO 2.0引入了新的异步通道的概念,并提供了对异步文件通道和异步套接字通道的实现。(基于NIO)
Asynchronous IO,字面意思即异步的IO,完全不阻塞,那我们看看这个的read操作图示:

NIO非阻塞异步图

通过图示可以很清楚得发现,如果是AIO发起read操作之后,kernel收到请求后会立即响应应用进程application,所以应用进程完全可以做其他的事,不会造成任何的block。待kernel第一、二阶段都已经完成之后,会给应用进程发送一个signal,告诉它read操作已经完成。所以AIO的特点是在IO的两个阶段都不会发生阻塞,而是全权交给系统内核才完成,内核完成后通过信号告知应用进程即可

五、各种I/O对比

属性\模型阻塞BIO非阻塞NIO异步AIO
blocking阻塞并同步非阻塞但同步非阻塞并异步
线程数(server:client)1:11:N0:N
复杂度简单较复杂复杂
吞吐量

具体使用得依据业务的实际应用场景和性能需求而定,如果客户端很少,并发量不大,那么完全可以选择BIO,不过得加入线程池管理;相反要求并发较高的话,就应该采用NIO框架了。

六、简单总结

BIO、NIO、AIO概念认知:

  • Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
  • Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
  • Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

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

  • BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
  • NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
  • AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值