`
maimode
  • 浏览: 412192 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

NIO BIO AIO

阅读更多

 

推荐阅读:http://blog.csdn.net/historyasamirror/article/details/5778378

 

一、 Reactor and Proactor

IO读写时,多路复用机制都会依赖对一个事件多路分离器,负责把源事件的IO 事件分离出来,分别到相应的read/write事件分离器  。涉及到事件分离器的两种模式分别就是 Reactor和Proactor,Reactor是基于同步IO的,Proactor是基于异步IO的  。

在Reactor模式中,事件分离者等待某个事件或者可应用或个操作的状态发生(比如文件描述符可读写,或者是socket可读写),事件分离者就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作  。

在Proactor模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的  。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调函数等信息  。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调  。举例来说,在Windows上事件处理者投递了一个异步IO操作(称有 overlapped的技术),事件分离者等IOCompletion事件完成. 这种异步模式的典型实现是基于操作系统底层异步API的,所以我们可称之为“系统级别”的或者“真正意义上”的异步,因为具体的读写是由操作系统代劳的  。

举个例子,将有助于理解Reactor与Proactor二者的差异,以读操作为例(类操作类似)  。

在Reactor中实现读:

- 注册读就绪事件和相应的事件处理器

- 事件分离器等待事件

- 事件到来,激活分离器,分离器调用事件对应的处理器  。

- 事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权  。

与如下Proactor(真异步)中的读过程比较:

- 处理器发起异步读操作(注意:操作系统必须支持异步IO)  。在这种情况下,处理器无视IO就绪事件,它关注的是完成事件  。

- 事件分离器等待操作完成事件

- 在分离器等待过程中,操作系统利用并行的内核线程执行实际的读操作,并将结果数据存入用户自定义缓冲区,最后通知事件分离器读操作完成  。

- 事件分离器呼唤处理器  。

- 事件处理器处理用户自定义缓冲区中的数据,然后启动一个新的异步操作,并将控制权返回事件分离器  。

可以看出,两个模式的相同点,都是对某个IO事件的事件通知(即告诉某个模块,这个IO操作可以进行或已经完成)  。在结构

上,两者也有相同点:demultiplexor负责提交IO操作(异步)、查询设备是否可操作(同步),然后当条件满足时,就回调handler;

不同点在于,异步情况下(Proactor),当回调handler时,表示IO操作已经完成;同步情况下(Reactor),回调handler时,表示

IO设备可以进行某个操作(can read or can write),handler这个时候开始提交操作。

 

二、BIO、NIO、AIO

NIO通常采用Reactor模式,AIO通常采用Proactor模式  。AIO简化了程序的编写,stream的读取和写入都有OS来完成,不需要像NIO那样子遍历Selector  。Windows基于IOCP实现AIO,Linux只有eppoll模拟实现了AIO  。

Java7之前的JDK只支持NIO和BIO,从7开始支持AIO  。

 

4种通信方式:TCP/IP+BIO, TCP/IP+NIO, UDP/IP+BIO, UDP/IP+NIO  。

 

TCP/IP+BIO

Socket和ServerSocket实现,ServerSocket实现Server端端口监听,Socket用于建立网络IO连接  。

不适用于处理多个请求 1.生成Socket会消耗过多的本地资源  。2. Socket连接的建立一般比较慢  。

BIO情况下,能支持的连接数有限,一般都采取accept获取Socket以后采用一个thread来处理,one connection one thread  。无论连接是否有真正数据请求,都需要独占一个thread  。

可以通过设立Socket池来一定程度上解决问题,但是使用池需要注意的问题是:1. 竞争等待比较多  。 2. 需要控制好超时时间  。

 

TCP/IP+NIO

使用Channel(SocketChannel和ServerSocketChannel)和Selector  。

Server端通常由一个thread来监听connect事件,另外多个thread来监听读写事件  。这样做的好处是这些连接只有在真是请求的时候才会创建thread来处理,one request one thread  。这种方式在server端需要支持大量连接但这些连接同时发送请求的峰值不会很多的时候十分有效  。

 

UDP/IP+BIO

DatagramSocket和DatagramPacket  。DatagramSocket负责监听端口以及读写数据,DatagramPacket作为数据流对象进行传输  。

UDP/IP是无连接的,无法进行双向通信,除非双方都成为UDP Server  。

 

UDP/IP+NIO

通过DatagramChannel和ByteBuffer实现  。DatagramChannel负责端口监听及读写  。ByteBuffer负责数据流传输  。

如果要将消息发送到多台机器,如果为每个目标机器都建立一个连接的话,会有很大的网络流量压力  。这时候可以使用基于UDP/IP的Multicast协议传输,Java中可以通过MulticastSocket和DatagramPacket来实现  。

Multicast一般多用于多台机器的状态同步,比如JGroups  。SRM, URGCP都是Multicast的实现方式  。eBay就采用SRM来实现将数据从主数据库同步到各个搜索节点机器  。

 

NIO主要原理和适用。

NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。

Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

 

参考:

http://blog.csdn.net/kexin_bo/article/details/6925351

http://19880512.blog.51cto.com/936364/381722

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics