时间轮算法

news2024/11/24 17:22:36

思考

假如现在有个任务需要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.coloradmin.cn/o/1033913.html

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

相关文章

兰贡生物:打造生物医药研发“独角兽”

当我们站在医学科学的最前沿,探索着无尽的健康奥秘时,生物制药行业正经历着前所未有的变革和机遇。新的疾病不断涌现,现有的治疗方法也在不断演进,这需要有着创新精神和科学追求的企业来推动新药研发的进程。值此时代背景下&#…

网络安全—黑客技术—自学笔记

目录梗概 一、自学网络安全学习的误区和陷阱 二、学习网络安全的一些前期准备 三、网络安全学习路线 四、学习资料的推荐 想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客! 网络安全可以基于攻击和防御视角来…

Linux常用命令—find命令大全

文章目录 一、find命令常用功能1、find命令的基本信息如下。2、按照文件名搜索3、按照文件大小搜索4、按照修改时间搜索5、按照权限搜索举例:6、按照所有者和所属组搜索7、按照文件类型搜索8、逻辑运算符 一、find命令常用功能 1、find命令的基本信息如下。 命令名…

力扣213打家劫舍2(简单动态规划)

题目描述: 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如…

1790_给通过USB连接到树莓派的NTFS硬盘设置固定的挂载名称

全部学习汇总: GreyZhang/little_bits_of_raspberry_pi: my hacking trip about raspberry pi. (github.com) 我用过好几个树莓派形式的单板电脑,但是遇到过磁盘挂载位置不确定的时候。有些甚至不会自动挂载。这些行为跟对应的OS的行为是相关的&#xff…

Mallox勒索病毒:最新变种.mallox_lab袭击了您的计算机?

引言 在数字化时代,数据是我们生活和工作的重要组成部分,但同时也引发了各种网络威胁,.mallox_lab勒索病毒便是其中之一。这种恶意软件以其加密文件并勒索赎金的方式而闻名,给个人和组织带来了巨大的风险和损失。本文将深入探讨.…

【小沐学C++】C++ MFC中嵌入64位ActiveX控件(VS2017)

文章目录 1、简介1.1 MFC1.2 ActiveX 2、VS2017添加ActiveX控件结语 1、简介 1.1 MFC Microsoft 基础类 (MFC) 库针对大部分 Win32 和 COM API 提供面向对象的包装器。 虽然此包装器可用于创建极为简单的桌面应用程序,但当你需要开发具有多个控件的更复杂的用户界…

你真的懂ArrayList吗?

ArrayList底层原理 ​ 1.ArrayList动态扩容的方法? 使用空参创建集合,在底层创建一个长度默认为0的数组;添加第一个元素时,底层会创建一个数组长度为10的数组;存满的时候,数组会自动扩容1.5倍;…

【算法思想-排序】按出现频率排序 - 力扣 1636

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

基于STM32+华为云IOT设计的智能车库管理系统

一、项目介绍 随着城市化进程和汽车拥有率的不断提高,停车难的问题也日益凸显。在城市中,停车场是一个非常重要的基础设施,但是传统的停车场管理方式存在很多问题,比如车位难以管理、停车费用不透明等。为了解决这些问题&#xf…

基于Vue+ELement搭建登陆注册页面实现后端交互

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《ELement》。🎯🎯 &#x1…

C语言入门Day_24 函数与指针

目录 前言: 1.指针和数组 2.函数和指针 3.易错点 4.思维导图 前言: 我们知道数组是用来存储多个数据的,以及我们可以用指针来指向一个变量。那么我们可以用指针来指向一个数组中的数据么? 指针除了可以像指向一个变量一样指…

【C++心愿便利店】No.6---C++之拷贝构造函数

文章目录 一、拷贝构造函数的引入二、拷贝构造函数 👧个人主页:小沈YO. 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:C 心愿便利店 🔑本章内容:拷贝构造函数 记得 评…

python安全工具开发笔记(四)——python网络编程

一、C/S架构 什么是C/S架构 C : Client S : Server。客户机和服务器结构。 Server 唯一的目的就是等待Client 的请求,Client 连上 Server 发送必要的数据,然后等待Server端完成请求的反馈。 C/S网络编程 Server端进行设置,首先创建一个通信…

怎么选择AI伪原创工具-AI伪原创工具有哪些

在数字时代,创作和发布内容已经成为了一种不可或缺的活动。不论您是个人博主、企业家还是网站管理员,都会面临一个共同的挑战:如何在互联网上脱颖而出,吸引更多的读者和访客。而正是在这个背景下,AI伪原创工具逐渐崭露…

ReadPaper论文阅读工具

之前看文献一直用的EndNote嘛,但是突然发现了它的一个弊端,就是说每次没看完退出去之后,下次再接着看的时候它不能保留我上一次的位置信息,又要重头开始翻阅,这让我感到很烦躁哈哈。(当然也不知道是不是我哪…

6条优势,anzo capital昂首资本相信MT5替代MT4的原因

投资者都知道MT5是在MT4基础上升级换代的多资产平台,MT5于2010年6月首次发布。anzo capital昂首资本认为MT5将完全取代MT4,就像MT4取代之前版本一样,因为有以下6条优势: 一.市场深度(DOM)数据。在MT4中,DOM几乎没有用…

GoAccess实时分析Nginx日志

GoAccess 是一个基于终端的实时 Web 日志分析仪。用 C 语言编写,它是快速,互动的,并以优雅而直观的方式显示日志。它提供了各种 Web 日志文件的支持,包括 Apache,Nginx,Caddy,Amazon S3 和 Clou…

c++STL概述

目录 STL基本概念 STL六大组件 STL的优点 STL三大组件 容器 算法 迭代器 普通的迭代器访问vector容器元素 算法for_each实现循环 迭代器指向的元素类型是自定义数据类型 迭代器指向容器 常用容器 string容器 string的基本概念 string容器的操作 string的构造函…

Python函数绘图与高等代数互融实例(六): 条形图|直方图|饼状图

Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数 Python函数绘图与高等代数互融实例(二):闪点函数 Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线 Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域 Python函数绘图与高等代数互融实例(五…