Netty-NIO线程模型

目录

一、NIO Epoll事件轮询模型

二、Redis线程模型

三、Netty线程模型


一、NIO Epoll事件轮询模型

对于 NIO 的 Selector,其非常强大,我们追踪一个open()方法的源码:

// 创建 selector,管理多个 channel
Selector selector = Selector.open();
// 进入.open()
public static ServerSocketChannel open() throws IOException {
    return SelectorProvider.provider().openServerSocketChannel();
}
// 进入 .provider()
public static SelectorProvider provider() {
    synchronized (lock) {
        if (provider != null)
            return provider;
        return AccessController.doPrivileged(
            new PrivilegedAction<SelectorProvider>() {
                public SelectorProvider run() {
                        if (loadProviderFromProperty())
                            return provider;
                        if (loadProviderAsService())
                            return provider;
                        provider = sun.nio.ch.DefaultSelectorProvider.create();
                        return provider;
                    }
                });
    }
}
// 进入 .create()
public static SelectorProvider create() {
    // Provider基于操作系统版本,我是mac这里是KQueueSelectorProvider
    // 如果是 Linux 则可能是 EpollSelectorProvider
    // 如果是 windows 则可能是 WindowsSelectorProvider
    return new KQueueSelectorProvider();
}

Epoll就是Linux版本下的多路复用实现,即 EpollSelectorProvider 就是关键所在。

EpollSelectorProvider 的实现本地调用的是本地方法,即Linux操作系统层面函数。

  1. Selector.open() --> SelectorProvider.provider() -->
    1. 内部实现类,通过 new EPollSelectorImpl(this) 方法 --> new EpollArrayWrapper() --> epfs=epollCreate() 调用本地方法 -->
    2. 调用 linux 系统函数 epfd=epoll_create(256) 创建了一个 epoll,selector就是对它的封装,内部有一个存储 channel 的数组
  2. socketChannel.register(Selector sel, int ops, Object att) --> SelctorImpl.register -->
    1. 底层就是调用 EpollSelectorImpl.implRegister --> 将fd(file descriptot文件描述符,就是 scoketChannel)添加到内部的集合里 pollWrapper.add(fd)
  3. selector.selector() --> SelectorImpl.select --> EpollSelectorImpl.doSelect -->
    1. 最终也是调用 pollWrapper.poll(timeout) --> 真正去注册绑定事件 updateRegistrations() -->
    2. 调用native方法epollWait()等待epfd(就是epoll实例)上的事件 --> 底层是linux内核函数 epoll_wait
      1. 当socket收到数据后,操作系统的中断程序调用回调函数会给epoll实例的事件就绪列表list里添加该socket引用(这块是操作系统实现的),当程序执行到epoll_wait时,如果rdlist已经引用了socket,那么epoll_wait直接返回,如果rdlist为空,阻塞进程
      2. 中断是系统用来响应硬件设备请求的一种机制,操作系统收到硬件的中断请求,会打断正在执行的进程,然后调用内核中的中断处理程序来响应请求
    3. 调用native方法epollCtl()进行事件绑定 --> 底层是linux内核函数 epoll_ctl

Epoll的事件轮询就是基于这三个底层函数来实现的(epoll_create、 epoll_wait、 epoll_ctl)

  1. int epoll_create():创建一个 epoll 实例,并返回一个非负数作为文件描述符,用于对 epoll 接口的所有后续调用
  2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event):使用文件描述符epfd引用的epoll实例,对目标文件描述符fd执行op操作。参数epfd表示epoll对应的文件描述符,参数fd表示socket对应的文件描述符。
    1. 监听selecotor的注册事件列表,他会注册channel到该列表,也会将有事件发生的channel转移到就绪事件列表rdlist
    2. 参数op由以下几个值
      1. EPOLL_CTL_ADD:注册新的fd到epfd中,并关联事件event
      2. EPOLL_CTL_DEL:从epfd中移除fd,并且忽略掉绑定的event,这时event可以为null
      3. EPOLL_CTL_MOD:修改已经注册的fd的监听事件
    3. 参数event是一个结构体
      struct epoll_event{
          _unit32_t events;
          epoll_data_t data;
      }
    4. events有很多可选值,这里列举几个常见的:
      1. EPOLLIN:表示对应的文件描述符是可读的;
      2. EPOLLERR:表示对应的文件描述符发生了错误;
      3. EPOLLOUT:表示对应的文件描述符是可写的;
    5. 成功返回0,失败返回-1
  3. int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout):等待文件描述符epfd上的事件。epfd是Epoll对应的文件描述符,events表示调用者所有可能事件的集合,maxevents表示最多等到多少个事件就返回,timeout是超时时间。
    1. 监听selector的就绪事件列表(rdlist)它有事件的话就会来处理,没有就阻塞

IO多路复用底层主要用的Linux内核函数(select,poll,epoll)来实现,windows不支持epoll实现,windows底层基于winsock2的select函数实现的(不开源)。

select

poll

epoll(jdk1.5及以上)

遍历

遍历

回调

数组

链表

哈希表

每次调用都进行线性遍历,时间复杂度为O(n)

每次调用都进行线性遍历,时间复杂度为O(n)

事件通知方式,每当有IO事件就绪,系统注册的回调函数就会被调用,时间复杂度O(1)

有上限

无上限

无上限

二、Redis线程模型

简单说一下redis的线程模型,在redis源码的src文件夹下有一个文件:ae_epoll.c 说一下里面的一些核心接口

  1. aeApiCreate(aeEventLoop *eventLoop):redis启动时回调该方法
    1. 调用函数 epoll_create(1024) 创建一个epoll
  2. aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask):
    1. 调用 epoll_ctl()
  3. aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp):
    1. 调用 epoll_wait()

Linux版本的Redis底层的通信就是基于epoll的事件轮询机制实现的。

三、Netty线程模型

核心就是在基础NIO多路复用的基础上做了大量的封装和优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值