Java新一代网络编程模型AIO原理及Linux系统AIO介绍

前言


从JDK 7版本开始,Java新加入的文件和网络io特性称为nio2(new io 2, 由于jdk1.4中已经有过一个nio了),包含了众多性能和功能上的改进,其中最重要的部分,就是对异步io的支持,称为Java AIO(asynchronous IO)。

由于AIO的实施需充分调用OS参与,IO须要操做系统支持、并发也一样须要操做系统的支持,因此性能方面不一样操做系统差别会比较明显。因此本文也附带介绍了Linux 2.6及之后版本新增的AIO特性(由于这跟Java AIO是对应关系)。

Java AIO


1基本原理


目前为止,Java共支持3种网络编程模型: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开始支持。

2AIO介绍


jdk在1.4版本的nio中提供了对非阻塞多路复用同步io模型的支持,可是在Windows上是基于较低效select/poll实现的。

jdk1.7中提供对aio的支持后,带来了两方面的好处:

  • Windows上可使用iocp了。
  • 简化了网络变成模型。异步io相比较非阻塞多路复用模型更易理解,开发更为简单。

和多路复用的java nio相比较,能够发现,异步io是在数据读取或者写入调用已经完成的时候,再通知调用者,而非阻塞多路复用io则是在有数据就绪,能够读写的时候通知调用者,读写仍然是由调用者执行而且是阻塞的(这意味着若是要同时进行其余工做,要控制读写操做不能阻塞太长时间或者须要将其放去单独的io线程执行)。

JDK7中的java aio新增的类和接口主要有:

  • AsynchronousServerSocketChannel ,对应于bio中的ServerSocket和nio中的ServerSocketChannel,用于server端的网络程序。
  • AsynchronousSocketChannel,对云关于bio中的Socket和nio中的SocketChannel,用于client端的网络程序。
  • CompletionHandler,回调接口,在socket进行accept/connect/read/write等操做时,能够传入一个CompletionHandler的实现,操做执行完毕后,会调用注册的CompletionHandler。

除了CompletionHandler这种回调方式,aio中还支持返回Future对象,使用Future来设定回调操做。

Linux AIO


1Linux AIO 简介


Linux 异步 I/O 是 Linux 内核中提供的一个至关新的加强。它是 2.6 版本内核的一个标准特性,可是咱们在 2.4 版本内核的补丁中也能够找到它。AIO 背后的基本思想是容许进程发起不少 I/O 操做,而不用阻塞或等待任何操做完成。稍后或在接收到 I/O 操做完成的通知时,进程就能够检索 I/O 操做的结果。

2Linux 的 I/O 模型


在深刻介绍 AIO API 以前,让咱们先来探索一下 Linux 上可使用的不一样 I/O 模型。这并非一个详尽的介绍,可是咱们将试图介绍最经常使用的一些模型来解释它们与异步 I/O 之间的区别。图 1 给出了同步和异步模型,以及阻塞和非阻塞的模型。

基本 Linux I/O 模型的简单矩阵:
Java新一代网络编程模型AIO原理及Linux系统AIO介绍_a.gif 

每一个 I/O 模型都有本身的使用模式,它们对于特定的应用程序都有本身的优势。

同步阻塞 I/O:
以下图所示:传统的阻塞 I/O 模型,这也是目前应用程序中最为经常使用的一种模型。其行为很是容易理解,其用法对于典型的应用程序来讲都很是有效。在调用 read 系统调用时,应用程序会阻塞并对内核进行上下文切换。而后会触发读操做,当响应返回时(从咱们正在从中读取的设备中返回),数据就被移动到用户空间的缓冲区中。而后应用程序就会解除阻塞(read 调用返回)。
Java新一代网络编程模型AIO原理及Linux系统AIO介绍_QQ20160514-0.png 
从应用程序的角度来讲,read 调用会延续很长时间。实际上,在内核执行读操做和其余工做时,应用程序的确会被阻塞。

同步非阻塞 I/O:
同步阻塞 I/O 的一种效率稍低的变种是同步非阻塞 I/O。在这种模型中,设备是以非阻塞的形式打开的。这意味着 I/O 操做不会当即完成,read 操做可能会返回一个错误代码,说明这个命令不能当即知足(EAGAIN 或 EWOULDBLOCK),以下图所示。
Java新一代网络编程模型AIO原理及Linux系统AIO介绍_c.gif 
非阻塞的实现是 I/O 命令可能并不会当即知足,须要应用程序调用许屡次来等待操做完成。这可能效率不高,由于在不少状况下,当内核执行这个命令时,应用程序必需要进行忙碌等待,直到数据可用为止,或者试图执行其余工做。正如图 3 所示的同样,这个方法能够引入 I/O 操做的延时,由于数据在内核中变为可用到用户调用 read 返回数据之间存在必定的间隔,这会致使总体数据吞吐量的下降。

异步阻塞 I/O:
另一个阻塞解决方案是带有阻塞通知的非阻塞 I/O。在这种模型中,配置的是非阻塞 I/O,而后使用阻塞 select 系统调用来肯定一个 I/O 描述符什么时候有操做。使 select 调用很是有趣的是它能够用来为多个描述符提供通知,而不只仅为一个描述符提供通知。对于每一个提示符来讲,咱们能够请求这个描述符能够写数据、有读数据可用以及是否发生错误的通知。
Java新一代网络编程模型AIO原理及Linux系统AIO介绍_QQ20160514-1.png 
select 调用的主要问题是它的效率不是很是高。尽管这是异步通知使用的一种方便模型,可是对于高性能的 I/O 操做来讲不建议使用。

异步非阻塞 I/O(AIO):
最后,异步非阻塞 I/O 模型是一种处理与 I/O 重叠进行的模型。读请求会当即返回,说明 read 请求已经成功发起了。在后台完成读操做时,应用程序而后会执行其余处理操做。当 read 的响应到达时,就会产生一个信号或执行一个基于线程的回调函数来完成此次 I/O 处理过程。
Java新一代网络编程模型AIO原理及Linux系统AIO介绍_e.gif 
在一个进程中为了执行多个 I/O 请求而对计算操做和 I/O 处理进行重叠处理的能力利用了处理速度与 I/O 速度之间的差别。当一个或多个 I/O 请求挂起时,CPU 能够执行其余任务;或者更为常见的是,在发起其余 I/O 的同时对已经完成的 I/O 进行操做。

3异步 I/O(AIO) 的动机


从前面 I/O 模型的分类中,咱们能够看出 AIO 的动机。这种阻塞模型须要在 I/O 操做开始时阻塞应用程序。这意味着不可能同时重叠进行处理和 I/O 操做。同步非阻塞模型容许处理和 I/O 操做重叠进行,可是这须要应用程序根据重现的规则来检查 I/O 操做的状态。这样就剩下异步非阻塞 I/O 了,它容许处理和 I/O 操做重叠进行,包括 I/O 操做完成的通知。

除了须要阻塞以外,select 函数所提供的功能(异步阻塞 I/O)与 AIO 相似。不过,它是对通知事件进行阻塞,而不是对 I/O 调用进行阻塞。

总结


使用异步 I/O(AIO)能够帮助咱们构建 I/O 速度更快、效率更高的应用程序。若是咱们的应用程序能够对处理和 I/O 操做重叠进行,那么 AIO 就能够帮助咱们构建能够更高效地使用可用 CPU 资源的应用程序。

尽管这种 I/O 模型与在大部分 Linux 应用程序中使用的传统阻塞模式都不一样,可是异步通知模型在概念上来讲却很是简单,能够简化咱们的设计。

更多资料


更多网络编程资料:http://www.52im.net/forum.php?mod=collection&action=view&ctid=8

一篇提到AIO的大型应用架构实践的文章:http://www.52im.net/thread-304-1-1.htmlphp

原文章地址:http://www.52im.net/thread-306-1-1.htmlhtml