当前位置: 首页 > news >正文

Netty NioEventLoop详解

文章目录

  • 前言
  • 类图
  • 主要功能
  • NioEventLoop如何实现事件循环
  • NioEventLoop如何处理多路复用
  • Netty如何管理Channel和Selector
      • 管理Channel
      • 管理Selector
      • 注意事项


前言

Netty通过事件循环机制(EventLoop)处理IO事件和异步任务,简单来说,就是通过一个死循环,不断处理当前已发生的IO事件和待处理的异步任务。
① NioEventLoop是一个基于JDK NIO的异步事件循环类,它负责处理一个Channel的所有事件在这个Channel的生命周期期间。

② NioEventLoop的整个生命周期只会依赖于一个单一的线程来完成。一个NioEventLoop可以分配给多个Channel,NioEventLoop通过JDK Selector来实现I/O多路复用,以对多个Channel进行管理。

③ 如果调用Channel操作的线程是EventLoop所关联的线程,那么该操作会被立即执行。否则会将该操作封装成任务放入EventLoop的任务队列中。

④ 所有提交到NioEventLoop的任务都会先放入队列中,然后在线程中以有序(FIFO)/连续的方式执行所有提交的任务。

⑤ NioEventLoop的事件循环主要完成了:

  • 已经注册到Selector的Channel的监控,并在感兴趣的事件可执行时对其进行处理;
  • 完成任务队列(taskQueue)中的任务,以及对可执行的定时任务和周期性任务的处理(scheduledTaskQueue中的可执行的任务都会先放入taskQueue中后,再从taskQueue中依次取出执行)。

类图

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

主要功能

NioEventLoop 主要负责以下几个方面的功能:

  1. 事件循环NioEventLoop 是一个单线程的事件循环,它不断地轮询注册在其上的 Channel,看是否有就绪的 I/O 事件(如读、写、连接等),然后进行相应的处理。
  2. 任务执行:除了处理 I/O 事件外,NioEventLoop 还负责执行定时任务和普通任务。这些任务可以是用户自定义的,也可以是 Netty 框架内部的。
  3. Channel 的注册与注销:Netty 中的 Channel 在创建后需要注册到一个 EventLoop 上,这样它才能开始处理 I/O 事件。同样地,当 Channel 不再需要时,也需要从 EventLoop 上注销。
  4. Selector 的管理NioEventLoop 内部使用 Java NIO 的 Selector 来轮询 Channel 的就绪状态。它负责 Selector 的创建、销毁以及选择操作。

在 Netty 中,通常会有多个 NioEventLoop 实例,它们通常与多线程模型结合使用,以实现真正的并发处理。每个 NioEventLoop 负责处理一组 Channel 的 I/O 事件,这样可以将不同的 Channel 分布到不同的线程上,从而实现并发处理。

总的来说,NioEventLoop 是 Netty 中负责处理 I/O 事件和任务执行的核心组件,它使得 Netty 能够高效地处理大量的网络连接和 I/O 操作。

NioEventLoop如何实现事件循环

NioEventLoop在Netty中实现事件循环的过程是Netty网络框架的核心机制之一,它结合了Java NIO的非阻塞特性和事件驱动模型,以高效地处理网络事件。以下是NioEventLoop如何实现事件循环的详细过程:

  1. 轮询就绪事件
    在事件循环中,NioEventLoop调用Selectorselect()方法来等待Channel上就绪的事件。select()方法会阻塞,直到至少有一个Channel的事件就绪,或者超时。

  2. 处理就绪事件
    一旦select()方法返回,NioEventLoop会获取就绪的Channel集合,并遍历这些Channel。对于每个就绪的Channel,NioEventLoop会根据其感兴趣的事件类型调用相应的处理器(通常是ChannelPipeline中的ChannelInboundHandler)来处理这些事件。这可能包括读取数据、写入数据、处理连接等。

  3. 执行非I/O任务
    除了处理I/O事件外,NioEventLoop还负责执行提交给它的非I/O任务。这些任务可能包括用户自定义的业务逻辑、回调方法等。NioEventLoop通常有一个任务队列,用于存储待执行的任务。在事件循环中,它会检查任务队列,并依次执行其中的任务。

  4. 定时任务调度
    NioEventLoop还支持定时任务的调度。用户可以将定时任务提交给NioEventLoop,并指定任务的执行时间或执行间隔。NioEventLoop内部会维护一个定时任务列表,并根据任务的调度信息在合适的时间点执行这些任务。

通过这个事件循环机制,NioEventLoop能够高效地处理大量的网络连接和I/O事件,同时保持单线程的事件处理模型,简化了并发控制和线程安全的处理。此外,Netty还通过多线程模型和多个NioEventLoop实例的配合使用,实现了真正的并发处理,从而能够处理更大规模的并发连接和事件。

    @Overrideprotected void run() {int selectCnt = 0;// 必须使用死循环不断进行事件轮询,获取任务和通道的 IO 事件for (;;) {try {int strategy;try {/*** 返回处理策略,就分为两种:* 有任务 hasTasks() == true,就不能等待IO事件了,先直接调用 selectNow() 方法,* 获取当前准备好IO 的通道channel 的数量(0 表示一个都没有),处理 IO 事件 和任务。** 没有任务 hasTasks() == false,返回 SelectStrategy.SELECT (是负数),* 没有要及时处理的任务,先阻塞等待 IO 事件*/strategy = selectStrategy.calculateStrategy(selectNowSupplier, hasTasks());switch (strategy) {case SelectStrategy.CONTINUE:continue;case SelectStrategy.BUSY_WAIT:// fall-through to SELECT since the busy-wait is not supported with NIOcase SelectStrategy.SELECT:// 返回下一个计划任务准备运行的截止时间纳秒值long curDeadlineNanos = nextScheduledTaskDeadlineNanos();if (curDeadlineNanos == -1L) {// 返回 -1,说明没有下一个计划任务,// 将 curDeadlineNanos 设置为 NONE,// 调用 selector.select 方法时,就没有超时,// 要无限等待了,除非被唤醒或者有准备好的 IO 事件。curDeadlineNanos = NONE;}// 设置 超时等待时间nextWakeupNanos.set(curDeadlineNanos);try {if (!hasTasks()) {// 当前没有任务,那么就通过 selector 查看有没有 IO 事件// 并设置超时时间,超时时间到了那么就要执行计划任务了// 如果 curDeadlineNanos 是 NONE,就没有超时,无限等待。strategy = select(curDeadlineNanos);}} finally {// 这个更新只是为了帮助阻止不必要的选择器唤醒,// 所以使用lazySet是可以的(没有竞争条件)nextWakeupNanos.lazySet(AWAKE);}// fall throughdefault:}} catch (IOException e) {// 如果我们在这里接收到IOException,那是因为Selector搞错了。// 让我们重新构建选择器并重试。// https://github.com/netty/netty/issues/8566rebuildSelector0();selectCnt = 0;handleLoopException(e);continue;}/*** 代码走到这里,* 要么有 IO 事件,即 strategy >0* 要么就是有任务要运行。* 如果两个都不是,那么就有可能是 JDK 的 epoll 的空轮询 BUG*/selectCnt++;cancelledKeys = 0;needsToSelectAgain = false;final int ioRatio = this.ioRatio;boolean ranTasks;if (ioRatio == 100) {// 如果 ioRatiotry {if (strategy > 0) {processSelectedKeys();}} finally {// 确保运行了所有待执行任务,包括当前时间已经过期的计划任务ranTasks = runAllTasks();}} else if (strategy > 0) {// strategy > 0 说明有 IO 事件,// 那么需要调用 processSelectedKeys() 方法,执行 IO 时间final long ioStartTime = System.nanoTime();try {processSelectedKeys();} finally {// 计算 IO 操作花费的时间final long ioTime = System.nanoTime() - ioStartTime;// 按照比例计算可以运行任务的超时时间 ioTime * (100 - ioRatio) / ioRatio,// 超时时间到了,即使还有任务没有运行,也直接返回了,等下一个周期在运行这些任务ranTasks = runAllTasks(ioTime * (100 - ioRatio) / ioRatio);}} else {// strategy == 0 说明没有 IO 事件,不用处理 IO 了// 调用 runAllTasks(0) 方法,超时时间为0,这将运行最小数量的任务ranTasks = runAllTasks(0);}if (ranTasks || strategy > 0) {// 要么有任务运行,要么有 IO 事件处理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)) {// 即没有任务运行,也没有IO 事件处理,就有可能是 JDK 的 epoll 的空轮询 BUG// 调用 unexpectedSelectorWakeup(selectCnt) 方法处理。// 可能会重新建立 SelectselectCnt = 0;}} catch (CancelledKeyException e) {// Harmless exception - log anywayif (logger.isDebugEnabled()) {logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector {} - JDK bug?",selector, e);}} catch (Error e) {throw e;} catch (Throwable t) {handleLoopException(t);} finally {// Always handle shutdown even if the loop processing threw an exception.try {if (isShuttingDown()) {// 如果事件轮询器开始 shutdown,就要关闭 IO 资源closeAll();if (confirmShutdown()) {return;}}} catch (Error e) {throw e;} catch (Throwable t) {handleLoopException(t);}}}}

NioEventLoop如何处理多路复用

NioEventLoop 在 Netty 中处理多路复用的方式主要是基于 Java NIO 的非阻塞特性和选择器(Selector)机制。多路复用允许单个线程同时处理多个通道(Channel)的 I/O 事件,从而提高了系统的吞吐量和响应速度。

以下是 NioEventLoop 如何处理多路复用的具体步骤:

  1. 初始化与注册

    • NioEventLoop 在初始化时创建一个 Selector 对象,用于监控多个 Channel 的状态。
    • 当一个 Channel 需要处理 I/O 事件时,它会被注册到 NioEventLoopSelector 上,并指定感兴趣的事件类型(如读、写等)。
  2. 轮询就绪事件

    • NioEventLoop 进入事件循环,调用 Selectorselect() 方法等待通道上就绪的事件。
    • select() 方法会阻塞,直到至少有一个 Channel 的事件就绪,或者超时。
  3. 处理就绪事件

    • select() 方法返回时,NioEventLoop 获取就绪的 Channel 集合。
    • 对于每个就绪的 ChannelNioEventLoop 根据其感兴趣的事件类型调用相应的处理器(如 ChannelInboundHandler)来处理这些事件。
  4. 多路复用核心

    • Selector 的核心作用在于它能够同时监控多个 Channel,并且只选择那些处于就绪状态的 Channel 进行处理。
    • 通过这种方式,NioEventLoop 可以使用单个线程高效地处理大量并发的 Channel,而无需为每个 Channel 创建一个独立的线程。
  5. 异步非阻塞通信

    • 由于 Netty 采用了异步通信模式,NioEventLoop 中的 IO 操作(如读、写)都是非阻塞的。
    • 这意味着当一个 IO 操作不能立即完成时(例如,等待数据从网络读取),线程不会被阻塞,而是可以继续处理其他任务或事件。
  6. 任务调度与执行

    • 除了处理 I/O 事件外,NioEventLoop 还负责执行提交给它的任务(如定时任务、用户自定义任务等)。
    • 这些任务与 I/O 事件一起,在 NioEventLoop 的事件循环中得到调度和执行。

Netty如何管理Channel和Selector

管理Channel

  1. 注册Channel
    当一个新的连接建立时,Netty会创建一个新的Channel实例(例如NioSocketChannelNioServerSocketChannel),并将其注册到NioEventLoop中的Selector上。注册过程包括将Channel添加到Selector的监控列表中,并设置其感兴趣的事件类型(如读、写、连接等)。

  2. 事件处理
    一旦Selector检测到某个Channel上有事件就绪(例如数据可读或可写),它会通知NioEventLoop。然后,NioEventLoop会调用相应的ChannelPipelineChannelHandler来处理这些事件。

  3. 关闭Channel
    当连接关闭时,Netty会注销Channel并从Selector的监控列表中移除它。同时,相关的资源也会被释放。

管理Selector

  1. 创建Selector
    NioEventLoop初始化时,它会创建一个Selector实例。这个Selector用于监控所有注册到该NioEventLoopChannel

  2. 轮询就绪事件
    NioEventLoop在事件循环中不断调用Selectorselect()方法来等待Channel上的事件就绪。一旦有事件就绪,Selector会返回这些事件的集合。

  3. 处理就绪事件
    NioEventLoop遍历Selector返回的就绪事件集合,并为每个事件调用相应的处理器。这通常涉及到调用ChannelPipeline中的ChannelHandler来处理这些事件。

  4. 优化Selector的使用
    Netty可能会使用多个SelectorNioEventLoop实例来优化性能,特别是在处理大量并发连接时。通过分散负载到多个线程和Selector上,Netty能够充分利用多核CPU的资源,提高吞吐量。

注意事项

  • 通常情况下,你不需要直接管理Selector。Netty的NioEventLoopChannel抽象为你提供了高级的API来处理I/O事件和连接。
  • 在编写自定义的ChannelHandler时,你需要关注如何处理事件,而不是如何管理ChannelSelector
  • 如果你需要执行定时任务或自定义的后台任务,可以使用NioEventLoop的任务队列来提交这些任务。这些任务会在事件循环的适当时候得到执行。

相关文章:

Netty NioEventLoop详解

文章目录 前言类图主要功能NioEventLoop如何实现事件循环NioEventLoop如何处理多路复用Netty如何管理Channel和Selector管理Channel管理Selector注意事项 前言 Netty通过事件循环机制(EventLoop)处理IO事件和异步任务,简单来说,就是通过一个死循环&…...

互联网大厂常见面试题目

1. CPU 的内存结构分为哪几层,分别是用于放什么数据的,如果一个函数里面有全局变量,局部变量和静态变量数据是如何存放的 2.C多态的实现原理是什么,父类是如何找到子类的虚函数实现的 3.操作系统中的虚拟内存实现机制是什么&…...

TechTool Pro for Mac v19.0.3中文激活版 硬件监测和系统维护工具

TechTool Pro for Mac是一款专为Mac用户设计的强大系统维护和故障排除工具。它凭借全面的功能、高效的性能以及友好的操作界面,赢得了广大用户的信赖和好评。 软件下载:TechTool Pro for Mac v19.0.3中文激活版 作为一款专业的磁盘和系统维护工具&#x…...

Linux-docker安装数据库redis

1.拉取redis镜像 docker pull redis # 下载最新的redis版本 docker pull redis:版本号 # 下载指定的redis版本ps:我这是已经下载最新版本的redis 2.查看redis镜像 docker images3.创建挂在路径并授权 mkdir -p /usr/local/redis/data mkdir -p /usr/local…...

LisJson解析配置表

每日一句:南来北往,不辜负生活,不迷失方向 [{ "ID": 0, "Name": "SmallPeople", "InitHealth": 100, "CostGold": 0, "MoveSpeed": 1…...

剑指offer10.斐波那契数列(动态规划)

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下: F(0) 0, F(1) 1 F(N) F(N - 1) F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 开始&#x…...

HarmonyOS实战开发-WebSocket的使用。

介绍 本示例展示了WebSocket的使用,包括客户端与服务端的连接和断开以及客户端数据的接收和发送。 WebSocket连接:使用WebSocket建立服务器与客户端的双向连接,需要先通过createWebSocket方法创建WebSocket对象,然后通过connect…...

【前缀合】Leetcode 连续数组

题目解析 525. 连续数组 寻找一个子数组,这个子数组中包含相同数目的0和1,但是这个子数组需要最长的 算法讲解 只需在[0,i]寻找一段区间使得这一段区间的和也等于sum即可 细节问题:1. 这里的哈希表的value存的是下标,因为需要找…...

一些优雅的算法(c++)

求最大公约数&#xff1a;辗转相除法 int gcd(int a,int b){return b0?a:gcd(b,a%b); }求最小公倍数&#xff1a;两整数之积除以最大公约数 int lcm(int a, int b){return a*b / gcd(a, b); }十进制转n进制&#xff1a; char get(int x){if(x<9){return x0;}else{return…...

Docker Desktop修改镜像存储路径 Docker Desktop Start ... 卡死

1、CMD执行wsl -l -v --all 2、Clean / Purge data 3、导出wsl子系统镜像: wsl --export docker-desktop D:\docker\wsl\distro\docker-desktop.tar wsl --export docker-desktop-data D:\docker\wsl\data\docker-desktop-data.tar4、删除现有的wsl子系统&#xff1a; wsl -…...

小型企业网络安全指南

许多小型企业刚刚起步&#xff0c;没有大公司所拥有的相同资源来保护其数据。他们不仅可能没有资金来支持多样化的安全计划&#xff0c;而且也可能没有人力或时间。 网络犯罪分子知道小型企业缺乏这些资源&#xff0c;并利用这些资源来谋取利益。遭受网络攻击后&#xff0c;小…...

springboot相关报错解决

Caused by: java.lang.ClassNotFoundException: 目录 Caused by: java.lang.ClassNotFoundException: org.springframework.context.event.GenericApplicationListener spring-boot-dependencies:jar:2.1.9.RELEASE was not found org.springframework.context.event.Generi…...

python 中 from import, __name__, __all__, __init__.py 作用,python的模块和导入包

from import 即类似于其他语言一样&#xff0c;是为了将别人写好的 .py 文件引入&#xff0c;并用于自己使用 例如我在一个.py 文件中写了很多用于计数学计算的方法&#xff0c;当别人想要调用我写好的这一套方法时 就需要先 from 我写的文件或其他人写好的文件&#xff08;py…...

Composer安装与配置详解

目录 第一章:Composer简介 1.1 什么是Composer? 1.2 Composer与传统的依赖管理工具的区别 1.3 Composer的发展历程 1.4 本章小结 第二章:Composer安装 2.1 全局安装与项目内安装 2.1.1 全局安装 安装步骤 2.1.2 项目内安装 安装步骤 2.2 不同操作系统下的安装方…...

A5 STM32_HAL库函数 之 CAN通用驱动程序所有函数的介绍及使用

A5 STM32_HAL库函数 之 CAN通用驱动程序所有函数的介绍及使用 1 CAN通用驱动程序所有函数预览1.1 HAL_CAN_Init1.2 HAL_CAN_ConfigFilter1.3 HAL_CAN_DeInit1.4 HAL_CAN_MspInit1.5 HAL_CAN_MspDeInit1.6 HAL_CAN_Transmit1.7 HAL_CAN_Transmit_IT1.8 HAL_CAN_Receive1.9 HAL_C…...

python如何判断图片为黑白还是彩色

基本原理 灰度图分两种情况&#xff1a; 单通道的图片 RGB 三通道的图片&#xff0c;但是每个通道的值相等 对于单通道的图片只需要判断图片的通道值是否为1 对于RGB模式的图片&#xff0c;情况稍稍复杂些。理论上只需判断RGB三个通道的值是否相等&#xff0c;但是现实中灰度…...

C语言进阶课程学习记录-main函数与命令行参数

C语言进阶课程学习记录-main函数与命令行参数 main函数验证以下4中定义是否正确实验-main的返回值cmd窗口 实验-main的输入参数cmd窗口 在main函数执其执行的函数实验-程序执行的第一个函数gcc编译器cmd窗口bcc编译器 小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&…...

Utilize webcam to capture photo with camera

1. Official Guide& my github Official course my github 2. Overcome Webcam js Error in Chrome: Could not access webcam link 直接把代码拷贝到本机的下述目录下 To ignore Chrome’s secure origin policy, follow these steps. Navigate to chrome://flags/#un…...

【uniapp】开发微信小程序 — 注意事项

底部导航栏 (tabBar) 图标的正确做法&#xff1a; 1、图片的标准尺寸为 81px * 81px&#xff0c;该尺寸在官方的文档中有明确的说明&#xff0c;可以参考微信小程序全局配置文档中对 iconPath 属性的说明。 2、为了保持良好的间距&#xff0c;图片的内容区域设置 60px* 比较好&…...

the python tutorial

Using the Python Interpreter Using Python as a Calculator To do floor division and get an integer result you can use the // operator Problem Solving with Algorithms and Data Structures using Python 首先将其拉到本地&#xff1f; 按照craft的方式走一遍&…...

AIoT人工智能物联网之AI 实战

1. jetson-inference 入门 jetson-inference是官方推出的体验套件,提供了三种最常见的AI应用于计算机视觉的类型,imagenet用于 图像辨识 ( Image Recognition )、detectNet用于对象辨识 ( Object Detection )、segNet用于语义分割 可以先使用windows下载 jetson-inference(因…...

Python 大麦抢票脚本

请注意&#xff0c;编写或使用抢票脚本可能违反相关网站的服务条款和法律法规。以下内容仅供学习和了解技术原理之用&#xff0c;不鼓励或支持任何违反规定的行为。 在Python中编写大麦网抢票脚本通常涉及以下几个步骤&#xff1a; ### 1. 分析网站结构 - 使用浏览器的开发者…...

前端开发攻略---用JavaScript打造炫酷数字变化动画效果:手写实现你的自定义动画函数!支持更改任意数字、动画速度

1、演示 2、介绍 这篇文章将向您展示如何使用JavaScript来创建一个自定义的动画函数&#xff0c;以实现数字变化效果。我们将深入了解前端动画的本质&#xff0c;并通过手写代码来实现这个炫酷的数字变化动画效果。您将学到如何利用JavaScript来操作DOM元素&#xff0c;控制动画…...

【学习】移动端兼容性测试有什么方法及重要性

随着移动互联网的快速发展&#xff0c;移动应用程序已经成为人们日常生活中不可或缺的一部分。然而&#xff0c;由于各种移动设备的硬件和软件差异&#xff0c;移动应用程序的兼容性问题也越来越突出。因此&#xff0c;移动端兼容性测试成为了一个重要的环节&#xff0c;它可以…...

记录linux从0部署java项目(宝塔)

目录 一、安装宝塔可视化界面 二、部署前端 三、部署后端 1、配置并连接Mysql数据库 2、配置并连接redis 3、安装jdk 这里先记录一个安装后遇到的问题 安装openJDK 四、检查 一、安装宝塔可视化界面 宝塔面板下载&#xff0c;免费全能的服务器运维软件 运行安装脚本 安…...

Python的时间和日期:探索datetime模块

&#x1f680; 个人主页&#xff1a;xmp65535 &#x1f680; 专栏&#xff1a;python技术专栏 目录 一、前言 二、datetime 模块简介 三、基本使用 1.日期和时间的创建 2.获取当前日期和时间 3.时间戳与日期时间之间的转换 4.时间运算 5.格式化日期和时间 6.解析字符串…...

代理与反向代理

Java项目的代理与反向代理 1. 代理 定位&#xff1a;为客户端服务通信方向&#xff1a;客户端->代理服务器->远程服务器好处&#xff1a;对客户端行为进行过滤和控制&#xff1b;隐藏客户端IP地址&#xff1b;审计流量&#xff1b;缓存资源加快访问速度&#xff1b; 2…...

长风破浪会有时,直挂云帆济沧海

仅以此篇记录生活琐事&#xff0c;因为自己在初中就天天写日记&#xff0c;到了大学自己写日记的次数逐渐少了下来。 最近心不在焉&#xff0c;不知道为啥&#xff0c;也许是因为压力吧。在我这个年龄阶段的压力也许不一样吧&#xff0c;过几天又要参加自考的考试&#xff0c;自…...

jAavascript基础积累

深拷贝与浅拷贝 深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#xff09;是在编程中常用的概念&#xff0c;它们指的是复制对象或数组时的不同方式。让我们来详细解释它们&#xff0c;并列举一些例子&#xff1a; 浅拷贝&#xff08;Shallow C…...

神经网络训练中batch的作用

在神经网络训练中&#xff0c;batch的作用主要包括以下几个方面&#xff1a; 减少内存占用和计算成本&#xff1a;在训练神经网络时&#xff0c;需要加载并处理大量的数据。使用batch训练可以将数据分成较小的批次&#xff0c;每次处理一小部分数据&#xff0c;从而减少内存占用…...