Netty核心源码解析(三)--NioEventLoop

NioEventLoop介绍

NioEventLoop继承SingleThreadEventLoop,核心是一个单例线程池,可以理解为单线程,这也是Netty解决线程并发问题的最根本思路--同一个channel连接上的IO事件只由一个线程来处理,NioEventLoop中的单例线程池轮询事件队列,有新的IO事件或者用户提交的task时便执行对应的handler逻辑进行处理;

NioEventLoop循环执行三件事:

  1. 响应selector中的IO事件
  2. 检查任务队列中是否有用户提交的任务
  3. 检查定时任务是否到期,到期则移交至任务队列中

首先,一个NioEventLoop聚合一个selector对象,这个selector对象就是JDK NIO中的selector对象(Netty可以配置选择是否对JDK 中的selector优化,优化主要是对selectionkeys集合优化,后续详细解释),通过代码可以看到,NioEventLoop的构造器里完成了selector的创建----(具体的selector创建Netty通过继承了jdk的SelectorProvider来实现的)

 ,先看一下NioEventLoop的构造方法,NioEventLoop只提供了一个构造方法--

    NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,EventLoopTaskQueueFactory queueFactory) {super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory),rejectedExecutionHandler);this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");final SelectorTuple selectorTuple = openSelector();this.selector = selectorTuple.selector;this.unwrappedSelector = selectorTuple.unwrappedSelector;}

构造函数中主要完成了selector的创建,选择器的实现策略,任务队列的创建,

先大概说一下run()方法的逻辑--

  1. 调用selector.select方法获取就绪IO事件的个数
  2. 判断是否有task---非定时任务
  3. 更新下一次定时任务的执行时间
  4. 处理selectedKeys---处理IO事件
  5. 执行任务---
    1. 获取到期的定时任务
    2. 根据配置控制任务异步任务执行时间
  6. 空轮训问题的处理

看一下具体实现--

首先获取IO就绪IO事件的个数

strategy = selectStrategy.calculateStrategy(selectNowSupplier, hasTasks());

calculateStrategy方法 --

  1. 如果当前有任务,则返回selectNow()方法的值---就绪的selected keys 个数
  2. 如果没有任务则返回-1;

然后看一下strategy为-1 的时候--

//返回-1的时候表示没有任务,此时计算
case SelectStrategy.SELECT:long curDeadlineNanos = nextScheduledTaskDeadlineNanos();if (curDeadlineNanos == -1L) {curDeadlineNanos = NONE; // nothing on the calendar}nextWakeupNanos.set(curDeadlineNanos);try {
//如果还是没有任务就需要重新计算一下就绪IO事件的个数,所以第一步在没有任务的时候直接将strategy赋值为-1是为了给处理定时任务留机会;if (!hasTasks()) {strategy = select(curDeadlineNanos);}} finally {//他的更新只是为了阻止不必要的选择器唤醒,所以lazySet的使用是可以的(没有比赛条件)nextWakeupNanos.lazySet(AWAKE);}

taskQueue中没有任务的时候获取定时任务中最近要生效的任务时间,然后再执行一次select方法;

之后根据ioRation(ioRation默认为50)来处理channel的IO事件和执行taskQueue中的任务;这里分三种情况:

  1. ioRation为100的时候,处理所有的IO事件并执行taskQueue中的所有任务;
     if (ioRatio == 100) {try {if (strategy > 0) {processSelectedKeys();}} finally {// Ensure we always run tasks.ranTasks = runAllTasks();}}
  2. ioRation小于100并且有就绪的IO事件的时候,先处理所有的就绪IO事件,然后以处理IO事件的时间作为基准分配异步任务的执行时间
    else if (strategy > 0) {final long ioStartTime = System.nanoTime();try {processSelectedKeys();} finally {// Ensure we always run tasks.final long ioTime = System.nanoTime() - ioStartTime;ranTasks = runAllTasks(ioTime * (100 - ioRatio) / ioRatio);}}
  3. ioRation小于100且没有就绪IO事件的时候只执行一个异步任务
else {ranTasks = runAllTasks(0); // This will run the minimum number of tasks}

最后,判断是否发生了select是否发生了空轮训--
 

if (ranTasks || strategy > 0) {if (selectCnt > MIN_PREMATURE_SELECTOR_RETURNS && logger.isDebugEnabled()) {logger.debug("Selector.select() returned prematurely {} times in a row for Selector {}.",selectCnt - 1, selector);}selectCnt = 0;} else if (unexpectedSelectorWakeup(selectCnt)) { // Unexpected wakeup (unusual case)selectCnt = 0;}

至此,一次Eventloop循环就处理完了,总结一下---

  1. Eventloop是Netty运行的核心逻辑,主要处理三件事--IO读写事件,用户提交的异步任务,处理JDK中的空轮训问题;
  2. 核心逻辑体现在run()方法中;run()方法首先根据异步任务队列中是否有任务需要执行来决定是否需要处理定时任务;
  3. 如果有异步任务需要处理则同时获取就绪IO事件的个数;如果没有异步任务则计算定时任务的处理时间---处理完定时任务如果还是没有任务提交则轮询IO事件
  4. 根据配置控制时间执行IO事件和异步任务;

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

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

相关文章

2023谷歌开发者大会直播大纲「初稿」

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…

【java】【idea2023版】Springboot模块没有.iml文件的问题

目录 方法一: 1、首先鼠标选中对应的对应的模块 ,按两下Ctrl键 2、project中选择对应的模块 3、运行mvn idea:module 命令​编辑 方法二: 1、可以右键点击open Terminal 2、然后在打开的Terminal里输入 方法一: 1、首先鼠…

【Rust】Rust学习 第十八章模式用来匹配值的结构

模式是 Rust 中特殊的语法,它用来匹配类型中的结构,无论类型是简单还是复杂。结合使用模式和 match 表达式以及其他结构可以提供更多对程序控制流的支配权。模式由如下一些内容组合而成: 字面值解构的数组、枚举、结构体或者元组变量通配符占…

python VTK PyQt5 VTK环境搭建 创建 渲染窗口及三维模型,包含 三维模型交互;

目录 Part1. VTK 介绍 Part2. PyQt5 VTK环境搭建 安装Anaconda 自带Python Anaconda下载 安装PyQt5 安装 VTK Part3 :PyQt VTK 结合样例: Part1. VTK 介绍 VTK(visualization toolkit)是一个开源的免费软件系统,主要用于三维计算机图形…

数字孪生赋能工业制造,为制造业带来新机遇与挑战

数字孪生技术是利用模拟仿真技术将实体对象数字化的技术。它基于虚拟现实、人工智能和云计算等技术,能够创建与真实物体相同的数字模型,并通过实时监测和分析手段,为制造企业提供关于该物体的全面数据,从而优化产品开发和生产过程…

数据结构双向链表

Hello,好久不见,今天我们讲链表的双向链表,这是一个很厉害的链表,带头双向且循环,学了这个链表,你会发现顺序表的头插头删不再是一个麻烦问题,单链表的尾插尾删也变得简单起来了,那废…

jvm——内存模型

1.java内存模型 1.1 原子性 1.2 问题分析 这里与局部变量自增不同,局部变量调用iinc是在局部变量表槽位上进行自增。 静态变量是在操作数栈自增。 这里的主内存和工作内存时再JMM里的说法。 因为操作系统是时间片切换的多个线程轮流使用CPU. 1.3解决方法 JMM中…

C#矩阵XY排序

矩阵XY快速排序 using MyVision.Script.Method;public class MyScript : ScriptMethods {//struct MOTIONPOSXY_S{public double Pos_x;public double Pos_y;};//脚本执行该方法public bool Process(){//try{//脚本代码写在下方 List<double> PointX GetDoubleList(&qu…

Tensor-动手学深度学习-李沐_笔记

介绍 Tensor&#xff0c;又称"张量"&#xff0c;其实就是n维度数组。不同维度的Tensor示意图如下&#xff1a; 关于Tensor.reshape reshape函数可以处理总元素个数相同的任何新形状&#xff0c;【3&#xff0c;2&#xff0c;5】->【3&#xff0c;10】->【5&a…

[系统] 电脑突然变卡 / 电脑突然** / 各种突发情况解决思路

今天来公司办公&#xff0c;开机之后发现电脑出现各种问题&#xff0c;死机、卡顿、点什么都加载&#xff0c;甚至开一个文件夹要1分钟才能打开&#xff0c;花了2个小时才解决&#xff0c;走了很多弯路&#xff0c;其实早点想通&#xff0c;5分钟就能解决问题&#xff0c;所以打…

本地部署 Stable Diffusion(Mac 系统)

在 Mac 系统本地部署 Stable Diffusion 与在 Windows 系统下本地部署的方法本质上是差不多的。 一、安装 Homebrew Homebrew 是一个流行的 macOS &#xff08;或 Linux&#xff09;软件包管理器&#xff0c;用于自动下载、编译和安装各种命令行工具和应用程序。有关说明请访问官…

ICT产教融合创新实训基地物联网实训室建设方案

一、概述 1.1物联网定义 物联网工程&#xff08;Internet of Things Engineering&#xff09;是一种以信息技术&#xff08;IT&#xff09;来改善实体世界中人们生活方式的新兴学科&#xff0c;它利用互联网技术为我们的日常生活活动提供服务和增益&#xff0c;从而让各种智能…

什么是Sui Kiosk,它可以做什么,如何赋能创作者?

创作者和IP持有者需要一些工具帮助他们在区块链上实现其商业模式。Sui Kiosk作为Sui上的一种原语可以满足这种需求&#xff0c;为创作者提供动态选项&#xff0c;使他们能够在任何交易场景中设置完成交易的条件。 本文将向您介绍为什么要在SuiFrens中使用Sui Kiosk&#xff0c…

0基础学习VR全景平台篇 第90篇:智慧眼-数据统计

【数据统计】是按不同条件去统计整个智慧眼项目中的热点&#xff0c;共包含四大块&#xff0c;分别是数据统计、分类热点、待审核、回收站&#xff0c;下面我们来逐一进行介绍。 1、数据统计 ① 可以按所属分类、场景分组、所属场景、热点类型以及输入热点名去筛选对应的热点&…

Node.js 的 Buffer 是什么?一站式了解指南

在 Node.js 中&#xff0c;Buffer 是一种用于处理二进制数据的机制。它允许你在不经过 JavaScript 垃圾回收机制的情况下直接操作原始内存&#xff0c;从而更高效地处理数据&#xff0c;特别是在处理网络流、文件系统操作和其他与 I/O 相关的任务时。Buffer 是一个全局对象&…

【80天学习完《深入理解计算机系统》】第十天 3.3 条件码寄存器【CF ZF SF OF】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

利用敏捷开发工具实现敏捷项目管理的实践经验分享

Scrum中非常强调公开、透明、直接有效的沟通&#xff0c;这也是“可视化的管理工具”在敏捷开发中如此重要的原因之一。通过“可视化的管理工具”让所有人直观的看到需求&#xff0c;故事&#xff0c;任务之间的流转状态&#xff0c;可以使团队成员更加快速适应敏捷开发流程。 …

Python科研绘图--Task03

目录 图类型 关系类型图 散点图的例子 数据分布型图 rugplot例子 分类数据型图 ​编辑回归模型分析型图 多子图网格型图 FacetGrid() 函数 PairGrid() 函数 绘图风格、颜色主题和绘图元素缩放比例 绘图风格 颜色主题 绘图元素缩放比列 图类型 关系类型图 数据集变量…

浅析 GlusterFS 与 JuiceFS 的架构异同

在进行分布式文件存储解决方案的选型时&#xff0c;GlusterFS 无疑是一个不可忽视的考虑对象。作为一款开源的软件定义分布式存储解决方案&#xff0c;GlusterFS 能够在单个集群中支持高达 PiB 级别的数据存储。自从首次发布以来&#xff0c;已经有超过十年的发展历程。目前&am…

HAProxy+nginx搭建负载均衡群集

目录 一、常见的Web集群调度器 二、HAProxy群集介绍 1、Haproxy的特性 : 2、Haproxy常用的调度算法 ① 轮询调度&#xff08;Round Robin&#xff09; ② 最小连接数&#xff08;Least Connections&#xff09; ③ 基于来源访问调度算法&#xff08;Source Hashing&am…