【Netty源码】NioEventLoop源码剖析

本文深入剖析了Netty的NioEventLoop源码,包括NioEventLoopGroup的实例化过程,NioEventLoop的类层次结构,任务的执行流程,特别是selectNow和select方法的优化,以及如何处理I/O任务和非I/O任务。通过详细的源码分析,揭示了Netty在处理网络事件和任务调度上的高效策略。
摘要由CSDN通过智能技术生成

NioEventLoopGroup

1.NioEventLoopGroup的类层次图

这里写图片描述

2.NioEventLoopGroup 实例化过程

这里写图片描述

分析:

  • EventLoopGroup(其实是MultithreadEventExecutorGroup) 内部维护一个类型为 EventExecutor children 数组, 其大小是 nThreads, 这样就构成了一个线程池

  • 如果我们在实例化 NioEventLoopGroup 时, 如果指定线程池大小, 则 nThreads 就是指定的值, 反之是处理器核心数 * 2

  • MultithreadEventExecutorGroup 中会调用 newChild 抽象方法来初始化 children 数组

  • newChild方法重载,初始化EventExecutor时,实际执行的是NioEventLoopGroup中的newChild方法,所以,children元素的实际类型为NioEventLoop。

  • NioEventLoop 属性:

  • SelectorProvider provider 属性: NioEventLoopGroup 构造器中通过SelectorProvider.provider() 获取一个 SelectorProvider

  • Selector selector 属性: NioEventLoop 构造器中通过调用通过 selector = provider.openSelector() 获取一个 selector 对象.

NioEventLoop

1.NioEventLoop的类层次图

这里写图片描述

分析:

  • 类的主要继承结构是:
NioEventLoop -> SingleThreadEventLoop -> SingleThreadEventExecutor -> AbstractScheduledEventExecutor
  • 在 AbstractScheduledEventExecutor 中, Netty 实现了 NioEventLoop 的 schedule 功能, 即我们可以通过调用一个 NioEventLoop 实例的 schedule 方法来运行一些定时任务.

  • 在 SingleThreadEventLoop 中, 又实现了任务队列的功能, 通过它, 我们可以调用一个 NioEventLoop 实例的 execute 方法来向任务队列中添加一个 task, 并由 NioEventLoop 进行调度执行.

2.两种任务
  • NioEventLoop中维护了一个线程,线程启动时会调用NioEventLoop的run方法,执行I/O任务和非I/O任务:

  • I/O任务:selectionKey中ready的事件,如accept、connect、read、write等,由processSelectedKeys方法触发。

  • 非IO任务:添加到taskQueue中的任务,如register0、bind0等任务,由runAllTasks方法触发。

  • 两种任务的执行时间比由变量ioRatio控制,默认为50,则表示允许非IO任务执行的时间与IO任务的执行时间相等。

3.NioEventLoop.run 方法源码如下
protected void run() {
   
    for (;;) {
   
        boolean oldWakenUp = wakenUp.getAndSet(false);
        try {
   
            if (hasTasks()) {
   
                selectNow();
            } else {
   
                select(oldWakenUp);
                if (wakenUp.get()) {
   
                    selector.wakeup();
                }
            }

            cancelledKeys = 0;
            needsToSelectAgain = false;
            final int ioRatio = this.ioRatio;
            if (ioRatio == 100) {
   
                processSelectedKeys();
                runAllTasks();
            } else {
   
                final long ioStartTime = System.nanoTime();

                processSelectedKeys();

                final long ioTime = System.nanoTime() - ioStartTime;
                runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
            }

            if (isShuttingDown()) {
   
                closeAll();
                if (confirmShutdown()) {
   
                    break;
                }
            }
        } catch (Throwable t) {
   
            logger.warn("Unexpected exception in the selector loop.", t);

            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   
                // Ignore.
            }
        }
    }
}

分析:首先会调用hasTasks()方法判断当前taskQueue是否有元素。如果taskQueue中有元素,执行 selectNow() 方法,最终执行selector.selectNow(),该方法会立即返回。如果taskQueue没有元素,执行 select(oldWakenUp) 方法

4.selectNow方法源码如下
void selectNow() throws IOException {
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值