Netty源码三:NioEventLoop创建与run方法

news2024/11/15 11:50:20

1.入口

image.png
会调用到父类SingleThreadEventLoop的构造方法

2.SingleThreadEventLoop

image.png
继续调用父类SingleThreadEventExecutor的构造方法

3.SingleThreadEventExecutor

image.png
到这里完整的总结一下:

  1. 将线程执行器保存到每一个SingleThreadEventExcutor里面去
  2. 创建了MpscQueue,具体为什么,因为在NioEventLoop里面重写了newTaskQueue方法

image.png

  1. 等父类调用完毕,最后回到NioEventLoop里面,最重要的一件事:创建Selector

最后那一张图完整的总结一下:
image.png

4.NioEventLoop.run

4.1 调用入口

这里还是要回顾一下这个方法是什么时候调用的?
Netty在启动的时候,在调用config().group().register(channel) ,使用bossGroup做channel注册的时候,它会使用EventExecutorChooser找一个NioEventLoop然后去做注册,最终会调用到这个abstractChannel.register方法
image.png
一般来说,我们启动的时候,运行到这里,eventLoop会返回false,所以会调用到eventLoop.execute里面的方法,在这里我们就能找到这个NioEventLoop.run的调用地方
image.png
image.png
image.png
也就说在使用NioEventLoop将channel注册到selector的时候,会判断是不是eventloop线程调用,如果不是就会使用SingleThreadEventExecutor.execute执行,它会将NioEventLoop.run方法包装成一个runnable,然后创建一个线程并启动,然后就调用到NioEventLoop里面了

4.2 run方法


/**
     * todo select()                    检查是否有IO事件
     * todo ProcessorSelectedKeys()     处理IO事件
     * todo RunAllTask()                处理异步任务队列
     */
@Override
protected void run() {
    for (; ; ) {
        try {
            // todo hasTasks() true代表 任务队列存在任务

            switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                case SelectStrategy.CONTINUE:
                    continue;
                case SelectStrategy.SELECT:
                    // todo 轮询IO事件, 等待事件的发生, 本方法下面的代码是处理接受到的感性趣的事件, 进入查看本方法
                    select(wakenUp.getAndSet(false));

                    // wakenUp.compareAndSet(false, true)' is always evaluated
                    // before calling 'selector.wakeup()' to reduce the wake-up
                    // overhead. (Selector.wakeup() is an expensive operation.)
                    //
                    // However, there is a race condition in this approach.
                    // The race condition is triggered when 'wakenUp' is set to
                    // true too early.
                    //
                    // 'wakenUp' is set to true too early if:
                    // 1) Selector is waken up between 'wakenUp.set(false)' and
                    //    'selector.select(...)'. (BAD)
                    // 2) Selector is waken up between 'selector.select(...)' and
                    //    'if (wakenUp.get()) { ... }'. (OK)
                    //
                    // In the first case, 'wakenUp' is set to true and the
                    // following 'selector.select(...)' will wake up immediately.
                    // Until 'wakenUp' is set to false again in the next round,
                    // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
                    // any attempt to wake up the Selector will fail, too, causing
                    // the following 'selector.select(...)' call to block
                    // unnecessarily.
                    //
                    // To fix this problem, we wake up the selector again if wakenUp
                    // is true immediately after selector.select(...).
                    // It is inefficient in that it wakes up the selector for both
                    // the first case (BAD - wake-up required) and the second case
                    // (OK - no wake-up required).

                    if (wakenUp.get()) {
                        selector.wakeup();
                    }
                    // fall through
                default:
            }

            cancelledKeys = 0;
            needsToSelectAgain = false;
            final int ioRatio = this.ioRatio;  // todo 默认50
            // todo  如果ioRatio==100 就调用第一个     processSelectedKeys();  否则就调用第二个
            if (ioRatio == 100) {
                    try {
                        // todo 处理 处理发生的感性趣的事件
                        processSelectedKeys();
                    } finally {
                        // Ensure we always run tasks.
                        // todo 用于处理 本 eventLoop外的线程 扔到taskQueue中的任务
                        runAllTasks();
                    }
                } else {// todo 因为ioRatio默认是50 , 所以来else
                    // todo 记录下开始的时间
                    final long ioStartTime = System.nanoTime();
                    try {
                        // todo 处理IO事件
                        processSelectedKeys();
                    } finally {
                        // Ensure we always run tasks.
                        // todo  根据处理IO事件耗时 ,控制 下面的runAllTasks执行任务不能超过 ioTime 时间
                        final long ioTime = System.nanoTime() - ioStartTime;
                        // todo 这里面有聚合任务的逻辑
                        runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                    }
                }
            } catch (Throwable t) {
                handleLoopException(t);
            }
            // Always handle shutdown even if the loop processing threw an exception.
            try {
                if (isShuttingDown()) {
                    closeAll();
                    if (confirmShutdown()) {
                        return;
                    }
                }
            } catch (Throwable t) {
                handleLoopException(t);
            }
        }
    }


这里注释其实说得挺清楚,最后总结一下:

  1. select(wakenUp.getAndSet(false)):轮训io事件发生,当timeout或者有事件会break
  2. processSelectedKeys:处理io事件
  3. 运行taskQueue里面的任务

4.3 processSelectedKeys

在真正执行的时候,最终会走到processSelectedKeysOptimized,netty对底层selectKeys容器进行过优化,用数组代替了keyset
image.png

这里我为了debug,使用telnet localhost 8899, 接着就会进入到processSelectedKeysOptimized中
image.png
在走进processSelectedKey方法之后,最终会走到unsafe.read方法
image.png
image.png

5.AbstractNioMessageChannel

image.png
接着会调用到子类NioServerSocketChannel的doReadMessage(readBuf), 调用完子类之后,会通过pipline.fireChannelRead, 意思就是对于server端来说可读了,但是注意这时候传的是子类中创建的NioSocketChannel,说白了给server端一个NioSocketChannel,就是要创建新连接了。最终会调用到ServerBootstrapAcceptor的ChannelRead,具体看后面的ServerBootStrapAcceptor类
image.png

6.NioServerSocketChannel

image.png
这里主要做了几件事:

  1. SocketUtils.accpet接受连接,并创建jdk底层的socketChannel
  2. new NioSocketChannel:将jdk封装成NioSocketChannel,这里和创建NioServerSocketChannel的时候一样,不断的调用父类,同时创建NioServerChannel的pipline,!!!这里注意,这里会设置感兴趣的事件为read

image.png

7.ServerBootstrap#ServerBootstrapAcceptor

ServerBootstrapAcceptor是ServerBootstrap的内部类
之前AbstractNioMessageChannel里面的image.png,最终会调用到ServerBootstrapAcceptor的channelRead方法
image.png
简单的总结一下做了几件事:

  1. 给sockeChannel(也是这里的child)设置childHandler
  2. 使用childGroup.register 来完成socketChannel到Selector的注册,这里和SocketServerChannel到Selector的注册逻辑是一样的,都是从EventLoopGroup中选一个EventLoop(里面有Selector),然后调用jdk的register(eventloop.getSelector, 0, NioSocketChannel(netty对于socketChannel的包装))

8.AbstractChannel

childGroup.register -> MultithreadEventLoopGroup.register -> SingleThreadEventLoop.register -> AbstractChannel.register
image.png
image.png
AbstractChannel.abstractUnsafe.register
image.png
这一刻代码之前都讲过,就是把创建socketChannel注册到EventLoop上的Selector上去
AbstractChannel.register0():
image.png

  1. doRegister: 完成了SocketChannel到Selector的注册
  2. pipeline.invokeHandlerAddedIfNeeded: 这里会调用之前我们设置MyServerInitializer.initChannel(), 会往SocketChannel的pipeline中加入一系列读写用到的Handler

9.总结

最后那一张图总结一下:
image.png


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1421829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jenkins自动化打包

Jenkins自动化打包 下载安装 我们直接从官网https://www.jenkins.io/download/ 下载所需的Jenkins文件 如上图所示, 选择Windows版本,下面就是一路安装即可,需要注意的是,选择作为系统服务选项, 不要自己设置账号密码登录. Web配置 安装完根据提示在浏览器打开 http://lo…

详解SpringCloud微服务技术栈:深入ElasticSearch(1)——数据聚合

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:详解SpringCloud微服务技术栈:ElasticSearch实战(旅游类项目) 📚订阅专栏&#x…

【RT-DETR改进涨点】ResNet18、34、50、101等多个版本移植到ultralytics仓库(RT-DETR官方一比一移植)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文是本专栏的第一篇改进,我将RT-DETR官方版本中的ResNet18、ResNet34、ResNet50、ResNet101移植到ultralytics仓库,网上很多改进机制是将基础版本的也就是2015年发布的ResNet移植到ultralytics仓库中,但是其实…

【Emgu CV教程】6.6、图像平滑之GaussianBlur()高斯滤波

文章目录 一、介绍1.原理2.函数介绍 二、举例1.原始素材2.代码3.运行结果 一、介绍 1.原理 高斯滤波是Emgu CV里面最常用的滤波,因为它在平滑图像的同时,可以更好的保留轮廓和边缘信息。下面这段来自百度百科的介绍: 高斯滤波是一种线性平滑…

思腾合力深思系列「IW4230-4GR」可扩展处理器的多场景适配服务器

思腾合力深思系列IW4230-4GR,采用第四代Intel Xeon Eagle Stream可扩展处理器的多场景适配服务器,支持4张双宽GPU卡。 思腾合力深思系列IW4230-4GR GPU服务器/工作站支持双路第四代IntelXeon Eagle Stream系列可扩展处理器,具有高性能、高密度…

【史上最全的接口与抽象类】

Java异常处理与try-catch-finally 抽象类和接口是Java中用于实现抽象和多态的关键概念。 抽象类的定义和语法:接口的定义和语法:接口和抽象类的区别主要在以下几个方面: 抽象类和接口是Java中用于实现抽象和多态的关键概念。 抽象类的定义和…

【Java异常处理与try-catch-finally】

Java异常处理与try-catch-finally try块是被监视的代码块,可能会发生异常的地方。当try块中的代码抛出了异常,程序会立即转入catch块,catch块根据捕获的异常类型进行处理。 Java异常处理是一种机制,用于捕获并处理在程序执行过程中…

用GPT写PHP框架

参考https://www.askchat.ai?r237422 写一个mvc框架 上面是简单的案例,完整的PHP框架,其核心通常包含以下几个关键组件: 1. 路由(Routing):路由组件负责解析请求的URL,并将其映射到相应的控制…

CAD-autolisp(四)——编译

目录 一、编译1.1 界面操作1.2 生成的应用程序(二选一) 二、后续学习 一、编译 编译:lsp后缀名为原文件,后缀名为fas、vlx为编译后文件,其会把sld、dcl、lsp等文件都编译进一个应用程序文件中加载:cad命令…

写作业考试用ChatGPT,留学如何防范“学术不端”危机?

近日,哈佛校长克洛迪娜盖伊在校园“反犹风波”中因立场问题被迫辞职。此外,哈佛大学相关调查委员会还发现盖伊在学术论文中存在错误引用资料来源等问题。对于种种学术不端行为,留学生如何防范?在ChatGPT时代,出国留学如…

C++ 数论相关题目,博弈论,SG函数,集合-Nim游戏

给定 n 堆石子以及一个由 k 个不同正整数构成的数字集合 S 。 现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合 S ,最后无法进行操作的人视为失败。 问如果两人都采用最优策略,…

保护医疗数据不受威胁:MPLS专线在医疗网络安全中的角色

随着数字技术的快速发展,医疗行业正在经历一场革命。从电子健康记录到远程医疗服务,数字化不仅提高了效率,也带来了前所未有的挑战--尤其是关于数据安全和隐私保护的挑战。在这样的背景下,如何确保敏感的医疗数据安全传输&#xf…

Qt6入门教程 14:QToolButton

目录 一.简介 二.常用接口 1.void setMenu(QMenu * menu) 2.void setPopupMode(ToolButtonPopupMode mode) 3.void setToolButtonStyle(Qt::ToolButtonStyle style) 4.void setArrowType(Qt::ArrowType type) 5.void setDefaultAction(QAction * action) 三.实战演练 1…

C/C++ (stdio.h)标准库详解

cstdio,在C语言中称为stdio.h。该库使用所谓的流与物理设备(如键盘、打印机、终端)或系统支持的任何其他类型的文件一起操作。 在本文将会通过介绍函数参数,举出实际的简单例子来帮助大家快速上手使用函数。 目录 一、流 二、库函数 1、F…

Zerosync:构建基于STARK的Bitcoin证明系统

1. 引言 前序博客: BitcoinSTARK: ZeroSync & Khepri Robin Linus、Tino Steffens、Lukas George 等人成立了一个名为 ZeroSync 协会(ZeroSync Association)的瑞士非营利组织,该组织将牵头开发比特币证明系统。ZeroSync 于…

STM32——ADC

STM32——ADC 1.ADC介绍 ADC是什么? 全称:Analog-to-Digital Converter,指模拟/数字转换器! ADC性能指标 量程:能测量的电压范围分辨率:ADC能辨别的最小模拟量,通常以输出二进制数的位数表示&#xf…

春季选品策略:如何在Shopee平台上脱颖而出

在Shopee平台上进行春季选品时,卖家需要制定有效的策略来吸引消费者的注意并提高销售业绩。本文将介绍一些关键的选品策略,帮助卖家在春季市场中脱颖而出。 先给大家推荐一款shopee知虾数据运营工具知虾免费体验地址(复制浏览器打开&#xf…

嵌入式——模拟/数字转换器(ADC)补充

目录 一、ADC简介 二、ADC功能 1.电压输入范围 2.输入通道 3. 转换顺序 (1)规则序列 (2) 注入序列 4.触发源 5. 转换时间 (1) ADC时钟 (2) 采样时间 6. 数据寄存器 &am…

回归预测 | Matlab实现CPO-BiLSTM【24年新算法】冠豪猪优化双向长短期记忆神经网络多变量回归预测

回归预测 | Matlab实现CPO-BiLSTM【24年新算法】冠豪猪优化双向长短期记忆神经网络多变量回归预测 目录 回归预测 | Matlab实现CPO-BiLSTM【24年新算法】冠豪猪优化双向长短期记忆神经网络多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CPO-B…

字符串中的单词反转【leetcode】

本题选自leetcode图解算法数据结构一书 你在与一位习惯从右往左阅读的朋友发消息,他发出的文字顺序都与正常相反但单词内容正确,为了和他顺利交流你决定写一个转换程序,把他所发的消息 message 转换为正常语序。 注意:输入字符串…