01

您所在的位置:网站首页 nio模型 01

01

#01| 来源: 网络整理| 查看: 265

IO模型

在学习netty之前,需要对JAVA的io模型进行一个了解,因为netty就是基于NIO进行封装的,io模型简单来说就是用什么样的通道发送数据,在JAVA中,有三种类型,分别是BIO(同步阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)

BIO

BIO-同步阻塞,举一个例子,有这样一个场景,有10个烧水壶烧开水,一个线程停留在A烧水壶那里,直到A烧水壶烧开,才能进行B烧水壶烧水,也就是说的同步阻塞,其他烧水壶都在阻塞等待A烧水壶,当然这里也可以优化,我们可以开10个线程同时进行烧水,不过这个时候缺点就很明显了,相当于每来一个烧水壶(客户端)都要新开一个线程,会对资源进行浪费,所以BIO只适合客户端体量较小的场景。 在BIO场景中,read操作是阻塞操作。

image.png NIO

NIO-同步非阻塞,服务器实现模式为一个线程可以处理多个请求(连接) 还是和上面烧水一样的例子,NIO的工作模式就是只对外启动一个线程,然后这个线程不断的轮询所有的开水壶,看看水是否开了。 这个时候会有一个问题,就是假设开水壶有1W个,每次这个单线程需要轮询这1W个开水壶集合,性能会比较低,有大量的无效遍历,所以这个时候引入多路复用器selector(Selector.open()),每个client连接服务器时,会通过channel往selector上注册事件,注册完会返回一个selectionkey和channel通道绑定,客户端有新事件的时候,selector通过遍历selectionkey对事件的事件类型进行处理, 伪代码

while(true){ // // 阻塞等待需要处理的事件发生 selector.select(); Iterator selectorlist=selector.iterator(); while(iterator.next()){ if(读事件){ }else if(连接事件){ } } } image.png linux epoll函数

上图中有几个关键的方法:

Selector.open() //创建多路复用器

由于我们的生产应用一般都部署在linux环境下,这个方法和windows环境下看到的jdk源码不同,linux环境下最终是执行了epoll_create(256)函数,创建一个epoll实例,并返回一个非负数作为文件描述符,用于对epoll接口的所有后续调用。

socketChannel.register(selector, SelectionKey.OP_READ) //将channel注册到多路复用器上

对应linux函数 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);对文件进行相关操作,如ADD/MOD/DEL

selector.select() //阻塞等待需要处理的事件发生

对应linux函数 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);等待文件描述符事件发生

由于调用的都是linux自带的内核函数,采用的事件通知方式,每当有IO事件就绪,系统注册的回调函数就会被调用,时间复杂度O(1) redis模型也是基于epoll的NIO模型,epoll实例收集连接、读写事件,由一个服务端线程连续处理所有事件

AIO

AIO-异步非阻塞,由client完成后回调通知server服务端程序启动线程去处理, 一般适用于连接数较多且连接时间较长的应用。以烧水为例,不需要开一个线程去轮询所有水壶,而是在每个水壶上安装一个开关,水开后开关发出声音通知我去关火。

三者对比

借用网上的一张图

image.png


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3