为什么说netty是异步的?它所采用的模型不是NIO多路复用么?
一开始看到netty是异步的也是一脸懵逼,之前说的线程模型明明是同步的啊。上网查了下:
Netty说自己是异步事件驱动的框架,并没有说网络模型用的是异步模型,异步事件驱动框架体现在所有的I/O操作是异步的,所有的IO调用会立即返回,并不保证调用成功与否,但是调用会返回ChannelFuture,netty会通过ChannelFuture通知你调用是成功了还是失败了亦或是取消了。
io.netty.channel.Channel类的一段注释请参考。
All I/O operations are asynchronous.All I/O operations in Netty are asynchronous. It means any I/O calls willreturn immediately with no guarantee that the requested I/O operation hasbeen completed at the end of the call. Instead, you will be returned witha {@link ChannelFuture} instance which will notify you when the requested I/Ooperation has succeeded, failed, or canceled.
这个问题可以分为两部分:NIO为什么是同步非阻塞的?Netty是如何实现NIO的?那么首先需要回答是什么是同步/异步,什么是阻塞/非阻塞?
同步/异步和阻塞/非阻塞描述的都是IO操作。
同步和异步:
资料一
从操作系统角度来说,网络IO的数据拷贝主要分为两个阶段,一是数据准备阶段,二是数据从内核拷贝到用户中。
同步IO指的是数据从内核拷贝到用户时。发起该请求的线程会自己来拷贝数据(表现为线程阻塞拷贝)。
PS:一旦涉及到网络 IO必定会发生数据拷贝的阻塞(此阻塞非彼阻塞,这里的阻塞形容的是拷贝数据相对于CPU的速度来说是非常耗时的,看起来像线程阻塞了一样。我们常说的阻塞是线程挂起并让出CPU),只不过阻塞发生在其他的地方(自己来拷贝就是同步的,别人帮我拷贝就是异步的),因为IO必定会用到CPU,即使是零拷贝。
资料二
同步:
同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。
异步:
将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。
同步,是所有的操作都做完,才返回给用户结果。即写完数据库之后,在相应用户,用户体验不好。
异步,不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好
资料三
https://www.zhihu.com/question/19732473/answer/117012135
https://blog.csdn.net/weixin_34332905/article/details/92850983?utm_medium=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~default-1.baidujs&dist_request_id=1329187.26082.16179885380610395&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~default-1.baidujs
阻塞和非阻塞:
阻塞和非阻塞主要描述的是网络IO数据拷贝的第一个阶段。
阻塞指的是线程一直等待数据准备好,期间什么都不干,但是会让出CPU,这样其他线程可以执行(CPU的利用率比较高),数据准备好之后自己来拷贝数据。
非阻塞指的是在第一阶段,发起网络IO请求的时候会立即返回去干别的事情,但是会不断地进行询问数据是否准备好,这种方式称之为轮询。由于CPU要处理更多的系统调用(每次询问都是系统调用),这种模型的CPU利用率低。
同步IO包括阻塞IO、非阻塞IO和IO多路复用。
NIO是如何实现同步非阻塞的呢?
Java的NIO实现采用了同步非阻塞IO和IO多路复用,其核心组件是Selector。Selector会不断的主动的询问Channel是否有事件发生,有事件发生,会进行事件处理。
//java nio
while(true) {
......
selector.select(1); //不阻塞
Set<SelectionKey> selectionKeySet= selector.selectedKeys();
......
//处理selectionKeySet中事件,线程没有阻塞
}
//java socket处理连接,线程会阻塞
while(true) {
......
Socket socket = serverSocket.accept(); //阻塞
InputStream in = socket.getInputStream();
......
//处理in中内容
}
总结
Netty采用的是NIO其对Java的NIO进行了改进,其内部也封装了Selector和Channel,采用串行并发来提高效率。
Java的NIO采用的是Reactor线程模型中的单Reactor单线程模型(前台和服务员是一个人,全程为顾客服务,可以服务多个人),Netty的NIO采用的是主从Reactor模型,是多Reactor多线程模型。
Netty中常说的NIO与Netty的异步事件有什么关系?
没有关系。
Netty是异步事件驱动的框架,网络IO模型采用的是NIO(同步非阻塞IO)。异步事件驱动框架体现在所有的I/O操作是异步的,所有的IO调用会立即返回,并不保证调用成功与否,但是调用会返回ChannelFuture,netty会通过ChannelFuture通知你调用是成功了还是失败了亦或是取消了。
io.netty.channel.Channel类的一段注释请参考。
All I/O operations are asynchronous.
All I/O operations in Netty are asynchronous. It means any I/O calls will
return immediately with no guarantee that the requested I/O operation has
been completed at the end of the call. Instead, you will be returned with
a {@link ChannelFuture} instance which will notify you when the requested I/O
operation has succeeded, failed, or canceled.
所以所谓的异步是针对用户而言的,用户使用Channel进行IO操作,会立即返回。但是这个IO操作的任务是提交给了Netty的NIO底层去进行处理,所以我们说Netty的异步事件驱动与Netty底层基于NIO(同步非阻塞)是不矛盾的。