时间轮算法

思考

假如现在有个任务需要3s后执行,你会如何实现?

线程实现:让线程休眠3s

如果存在大量任务时,每个任务都需要一个单独的线程,那这个方案的消耗是极其巨大的,那么如何实现高效的调度呢?

时间轮算法就被提出来了

时间轮实现:下图是一个有12个时间格的时间轮,转完一圈需要12s。当我们需要新建一个3s后执行的定时任务,只需要将定时任务放在下标为3的时间格中即可。

当我们需要创建一个12s后执行的定时任务呢?(当前槽位为3)

添加刻度实现,按1秒为一个时间刻度,那么一天会有86400个刻度,当我继续添加一个任务,是86000秒后执行,那么其中大部分轮询都是空轮询,而且会浪费内存空间(每个刻度都有自己的任务队列)

这个时候可以引入“圈数/轮数”的概念,也就是说这个任务还是放在

下标为3的时间格中,不过它的圈数为1(圈数从0开始)。

当我们需要创建一个350s后自动完成的定时任务呢?

如果都用 round 来处理的话,那这个 round 将会变的非常大的一个数字,也会在任务列表中插入很多当前不需要执行的任务,如果每次都执行上面的逻辑,显然会浪费大量的资源。

时间轮

时间轮的数据结构

如上图所示,就是时间轮的一个基础结构,一个 存储定时任务的环形队列,底层采用数组实现,数组中的每个元素可以存放一个定时任务列表(TimerTaskList)。定时任务列表 是一个环形的双向链表,链表中的每一项表示的都是定时任务项(TimerTaskEntry),其中封装了真正的定时任务 TimerTask。

单层时间轮

现在我们不增加刻度,而是通过添加round属性来描述任务。假设我们时间大小设置为20s,我们添加三个任务:

  1. 10秒后执行的任务
  2. 30秒后执行的任务
  3. 50秒后执行的任务

那么这三个任务都在10刻度的任务队列中,分别为round=0, round=1, round=2。时间轮每移动一个刻度时,遍历任务队列取出round=0的任务执行,然后将其余的任务 round-1。

槽位计算公式:定时器放置的槽位 =(当前时间 + 定时器的延迟时间)%  槽位数量

(3+12)%12=3

10%20=10

30%20=10

50%20=10

任务执行轮次的计算公式: 定时器执行圈数 = ((任务执行时间 - 当前时间)/ 固定单位时间)% 槽位数量

((12-0)/12)%12 = 0

((10-0)/20)%20 = 0

((30-0)/20)%20 = 1

((50-0)/20)%20 = 2

基于round的时间轮虽然解决了浪费内存空间的问题,但当时间刻度小,任务队列长的时候会增加耗时。

多层时间轮

与基于round的时间轮不同,分层时间轮采用层级联动的方式,具有以下特点:

  1. 不做遍历计算round,每一个刻度中的任务都是应该执行的。
  2. 当任务执行时间超过当前刻度范围时,进入下一层时间轮的范围。
  3. 定时任务通过升级和降级来转移队列中的位置。

基本模型构成

  • tickMs(基本时间跨度):时间轮由多个时间格组成,每个时间格代表当前时间轮的基本时间跨度(tickMs)。
  • wheelSize(时间单位个数):时间轮的时间格个数是固定的,可用(wheelSize)来表示,那么整个时间轮的总体时间跨度(interval)可以通过公式 tickMs × wheelSize计算得出

上图的时间轮,设第 1 层的时间精度为 1s,第 2 层的时间精度为 20s,第 3 层的时间精度为 400s。假如我们需要添加一个 350s 后执行的任务 A 的话(当前时间是 0s),这个任务会被放在第 2 层(因为第二层的时间跨度为 20*20=400>350)的第 350/20=17 个时间格子。

当第一层转了 17 圈之后,时间过去了 340s ,第 2 层的指针此时来到第 17 个时间格子。此时,第 2 层第 17 个格子的任务会被降级到第 1 层。

任务 A 当前是 10s 之后执行,因此它会被移动到第 1 层的第 10 个时间格子。

时间轮的应用

时间轮的思想应用范围非常广泛,各种操作系统的定时任务调度,Crontab、Dubbo、新版的XXL-JOB、还有基于java的通信框架Netty中也有时间轮的实现,几乎所有的时间任务调度系统采用的都是时间轮的思想。

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

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

相关文章

goadmin 学习笔记

1.安装命令行 Following three steps to run it. Note: now you can quickly start by doing like this. $ go install github.com/GoAdminGroup/admlatest $ mkdir new_project && cd new_project $ adm init Or (use adm whose version higher or equal than v1.…

2023年信创云管平台选哪家?咨询电话多少?

随着云计算和信创国产化的快速发展,越来越多企业需要支持信创系统的云管平台。但很多企业不知道市面上信创云管平台有哪些,也不知道选哪家?这里我们小编就给大家来回答一下。 2023年信创云管平台选哪家?咨询电话多少?…

剪映软件专业版的操作与使用,电脑版与手机版APP同步讲解

一、教程描述 什么是剪映?抖音官方推出的一款视频编辑工具,用于短视频的剪辑制作和在线发布,主要在手机端使用,同时支持PC端,操作简单易上手,功能也十分强大,使用过剪映的用户,都将…

基于量子粒子群算法(QPSO)优化LSTM的风电、负荷等时间序列预测算法(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

华硕 ASUS U303L 换国产致钛SSD固态硬盘记

ASUS U303L尽享丝滑体验——换装国产致钛SC001 1T SSD 华硕笔记本电脑款式年代久远,东芝的机械硬盘,没有安装SSD的笔记本电脑用久了,卡顿是难免的事情。更换国产致钛固态硬盘后,体验丝一般的感觉,非常成功&#xff01…

nginx: 部署前端项目的详细步骤(vue项目build打包+nginx部署)

目录 第一章 前言 第二章 准备工作 2.1 项目打包理解 2.1.1 打包命令 2.1.2 理解npm run serve/dev 和 npm run build命令 2.2 nginx参数配置理解 2.2.1 nginx常用基本命令 2.2.2 默认配置 2.2.3 搭建不同网站的站点 2.2.4 禁止访问的目录以及一键申请SSL证书验证目录…

【JDK 8-函数式编程】4.4 Supplier

一、Supplier 接口 二、实战 Stage 1: 创建 Student 类 Stage 2: 创建方法 Stage 3: 调用方法 Stage 4: 执行结果 一、Supplier 接口 供给型 接口: 无入参,有返回值(T : 出参类型) 调用方法: T get(); 用途: 如 无参的工厂方法&#x…

【js逆向实战】某讯漫画网站图片逆向

写在前面 本来想更安全开发系列,想着复现一下长亭的rad。里面涉及到好多js逆向的知识,正好学习了一波,本身js逆向也是一个大坑,说不定也能完善好多以前的爬虫项目。 学了也有一段时间了,来练练手吧 涉及到具体的隐私…

service

title: “Service” createTime: 2022-02-11T11:23:2008:00 updateTime: 2022-02-11T11:23:2008:00 draft: false author: “name” tags: [“service”] categories: [“linux”] description: “测试的” linux的Service之旅 1.service 服务权限 systemd有系统和用户区分&…

2023年9月26日,历史上的今天大事件早读

1620年9月26日大明皇帝朱常洛驾崩 1815年9月26日俄、普、奥三国在巴黎发表缔结“神圣同盟” 1841年9月26日清代思想家、诗人龚自珍逝世 1849年9月26日“生理学之父”巴甫洛夫诞生 1909年9月26日云南陆军讲武堂创办 1953年9月26日画家徐悲鸿逝世 1980年9月26日国际宇航联合…

【C++】构造函数和析构函数第一部分(构造函数和析构函数的作用)--- 2023.9.25

目录 前言初始化和清理的概念构造函数和析构函数的作用构造函数的作用析构函数的作用 使用构造函数和析构函数的注意事项默认的构造函数和析构函数结束语 前言 在使用c语言开发的项目场景中,我们往往会遇到申请空间的需求,同时也肯定遇到过程序运行一段…

phpstudy2016 RCE漏洞验证

文章目录 漏洞描述漏洞验证 漏洞描述 PHPStudyRCE(Remote Code Execution),也称为phpstudy_backdoor漏洞,是指PHPStudy软件中存在的一个远程代码执行漏洞。 漏洞验证 打开phpstudy2016,用bp自带的浏览器访问www目录下…

【Verilog 教程】4.8Verilog 过程连续赋值

关键词:deassign,force,release 过程连续赋值是过程赋值的一种。这种赋值语句能够替换其他所有 wire 或 reg 的赋值,改写了 wire 或 reg 型变量的当前值。 与过程赋值不同的是,过程连续赋值的表达式能被连续的驱动到 …

大数据Flink(八十六):DML:Group 聚合和Over 聚合

文章目录 DML:Group 聚合和Over 聚合 一、DML:Group 聚合

Spring面试题23:Spring支持哪些事务管理类型?Spring框架的事务管理有哪些优点?你更倾向用哪种事务管理类型?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring支持哪些事务管理类型? Spring 支持以下几种事务管理类型: 编程式事务管理:通过在代码中显式地使用事务管理 API(如 TransactionTempla…

Python+Django前后端分离

程序示例精选 PythonDjango前后端分离 如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助! 前言 这篇博客针对《PythonDjango前后端分离》编写代码,代码整洁,规则,易读。 学习与应…

第3章-指标体系与数据可视化-3.1.2-Seaborn绘图库

目录 3.1.2 Seaborn绘图库 1. 带核密度估计的直方图 2. 二元分布图 一维正态分布 联合分布函数 二元边际分布函数 二维正态分布 3. 热力图 附录 参考 3.1.2 Seaborn绘图库 Seaborn和Matplotlib类似,也是Python数据可视化库。不过,它是基于Matpl…

mlc-llm 推理优化和大语言模型搭建解析

0x0. 前言 本文解析一下mlc-llm(https://github.com/mlc-ai/mlc-llm)对大模型推理的流程以及使用的图优化,算子优化策略。mlc-llm的模型部署流程可以查看官方文档:https://mlc.ai/mlc-llm/docs/ ,也可以参考我前段时间…

如何计算3种卷积之后的尺寸(普通卷积,转置卷积,空洞卷积)

文章目录 前言一、普通卷积二、转置卷积三、空洞卷积 前言 三种卷积之后的feature map的尺寸如何计算。包括普通卷积,转置卷积,空洞卷积。可以在下面这个链接看到三种卷积的动态图。 卷积动态图 一、普通卷积 普通卷积比较简单了,其计算方式…

IEEE802.2之LLC(逻辑链路控制)

一、概念 IEEE 802.2 是一种用于局域网(LAN)和都会区域网(MAN)的数据链路层逻辑链路控制(LLC)的标准。它是 IEEE 802 系列标准中的一个组成部分,专门用于定义如何在数据链路层内进行帧的多路复用…