美文网首页
Blocking VS non-blocking IO

Blocking VS non-blocking IO

作者: 愚公300代 | 来源:发表于2016-08-26 10:55 被阅读767次

IO指Blocking IO

NIO指new/non-blocking IO

Blocking IO中,对于每一个连接,创建一个线程处理这个连接的IO事件,连接和处理线程之间有1:1的关系。连接数受到JVM线程数的限制。JVM最大线程数限制参考http://jzhihui.iteye.com/blog/1271122,最大线程数由操作系统支持线程数,java初始堆大小,最大堆大小以及每个线程栈大小决定。

NIO使用单个selector可处理多个连接。

IO核心代码

final Socket clientSocket = socket.accept();

new Thread(new Runnable() {

@Override

public void run() {

...

}

}).start();

服务端socket.accept()阻塞直至接受新的connection。

接受新的connection之后,建立新的线程,处理这个连接,每一个连接都有一个线程处理,连接数和线程数是1:1的关系。客户端并发的线程数由同时存活线程数决定。

NIO的基础概念

NIO使用selector-based方法来处理网络数据和事件(The NIO API uses a selector-based approach to handle network events and data)

ByteBuffer:数据容器(不影响原理的理解,之后再讲)。

NIO Selectors:Selector is a NIO component that determines if one or more channels are ready for reading and/or。

选择器:选择器是一个组件,这个组件可以决定此时是否有一个或多个的channels准备好进行读写。由于Selector可以处理多个连接,减轻了IO中的线程负担。

Channel: A channel represents a connection to an entity capable of performing IO operations such as a file or socket.

通道:通道是指连向可进行IO操作实体的连接。通道本质上是特殊的连接,特殊在其连接的对象都可进行IO操作。NIO的通道似乎都是双向的。

Selector的使用,需要5步

创建一个Selector,使得其它的Channel可以注册到Selector

在注册Channel时,要说明Selector对此Channel感兴趣的时间

OP_ACCEPT:socket-accept operations的操作位

OP_CONNECT:socket-connect

OP_READ:read operation

OP_WRITE:write operation

调用Selector.select()阻塞,指导上述事件发生

事件发生之后,可以获取到SelectionKey实例,每个实例都包括Channel的引用和实际发生的事件。

此版本NIO核心代码

serverChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {

try {

selector.select();

} catch (IOException ex) {

ex.printStackTrace();

// handle in a proper way

break;

}

Set readyKeys = selector.selectedKeys();

Iterator iterator = readyKeys.iterator();

while (iterator.hasNext()) {

SelectionKey key = (SelectionKey) iterator.next();

iterator.remove();

try {

if (key.isAcceptable()) {

ServerSocketChannel server = (ServerSocketChannel)

key.channel();

SocketChannel client = server.accept();

System.out.println("Accepted connection from " +

client);

client.configureBlocking(false);

client.register(selector, SelectionKey.OP_WRITE |

SelectionKey.OP_READ, ByteBuffer.allocate(100));

}

if (key.isReadable()) {

SocketChannel client = (SocketChannel) key.channel();

ByteBuffer output = (ByteBuffer) key.attachment();

client.read(output);

}

if (key.isWritable()) {

SocketChannel client = (SocketChannel) key.channel();

ByteBuffer output = (ByteBuffer) key.attachment();

output.flip();

client.write(output);

output.compact();

}

} catch (IOException ex) {

key.cancel();

try {

key.channel().close();

} catch (IOException cex) {

}

}

}

从代码中可以看出此版本NIO需要开发者检查网络事件发生,同时触发相应的处理逻辑。

NIO2

NIO允许分发IO操作,当IO操作完成时使用completion handler处理IO事件。completion handler的执行完全由底层系统决定,对开发者隐藏。同时保证了每个channel同时

只有一个completion handler在执行。

NIO2核心代码

channel.read(buffer, buffer,new EchoCompletionHandler(channel));

当读取的IO完成之后,自动执行Echo CompletionHandler的操作。

private final class EchoCompletionHandler implements

CompletionHandler {}

上述内容讲了

1. IO和NIO的本质区别:IO的thread-per-connection的本质以及NIO selector-based approch to handle network data and event.

2. IO实现,NIO1实现以及NIO2实现方式的区别,IO使用accept()阻塞等待连接发生之后,创建新的线程处理此连接;NIO1使用selector对channel进行监听,使用selector.select()阻塞直到某个channel准备好读或写,需要开发者检测事件的发生并提供相应的处理逻辑。NIO1是异步的,selector可监听多个channel,这本质上不同于IO;NIO2同样是基于selector但是NIO2的好处在于允许分发IO,并且提供了complete handler用于在IO完成时,自动执行,这种方法不需要检测事件是否发生,然后使用相应的处理逻辑,这一切由底层实现。


参考:《netty in action》

相关文章

网友评论

      本文标题:Blocking VS non-blocking IO

      本文链接:https://www.haomeiwen.com/subject/zwwhjttx.html