您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

那些惊艳的算法—时间轮算法

时间:2021-04-22 11:24:05  来源:今日头条  作者:鹅是程序猿

从定时任务说起

自然界中定时任务无处不在,太阳每天东升西落,候鸟的迁徙,树木的年轮,人们每天按时上班,每个月按时发工资、交房租,四季轮换,潮涨潮落,等等,从某种意义上说,都可以认为是定时任务。

大概很少有人想过,这些“定时”是怎样做到的。当然,计算机领域的同学们可能对此比较熟悉,毕竟工作中的定时任务也是无处不在的:每天凌晨备份一波数据库,每天9点发一波邮件,每天定时发送任务通知。

至于怎么实现的?很简单啊,操作系统的crontab,spring框架的quartz,实在不行JAVA自带的ScheduledThreadPool、c#的System.Timers都可以很方便的做到定时任务的管理调度。

初识时间轮

大概去年的时候,业务需要实现一个时间调度的工具,定时生成报表,同组的哥们没有采用任何框架,而是想了一个很取巧的办法:

启动时从DB读取cron表达式解析,算出该任务下次执行的时间。

下次执行的时间 - 当前时间 = 时间差。

向ScheduleThreadPool线程池中提交一个延迟上面算出来的时间差的执行的任务。

任务执行时,算一下这个任务下次执行的时间,算时间差,提交到线程池。

当任务需要取消时,直接调用线程池返回的Future对象的cancel()方法就行了。

当时稍微想了一ScheduleThreadPool是怎么做到定时执行提交过来的任务的,大概有个模糊的概念,后来就把这事忘了。再后来,一次在博客园上看到一篇文章,讲了一种叫做时间轮的定时任务调度思想,感觉想法很不错,当年那个模糊的概念似乎清晰了很多,再后来,一个偶然的机会,网上搜了一下,竟然有一篇专门讲解时间轮算法的论文,顿时兴奋无比,赶紧打印下来,在上班的地铁上读了半个月,总算读完了。

戳这里下载:《Hashed and Hierarchical Timing Wheels》

论文中的思路很简单但也十分巧妙,对算法不断地改进对比,各种操作系统,框架中的基于时间的调度算法都是基于时间轮的思想实现的。下面我们来看看,这个神奇的时间轮到底是怎样实现定时任务的调度的。

绝对时间和相对时间

定时任务一般有两种:

约定一段时间后执行。

约定某个时间点执行。

聪明的你会很快发现,这两者之间可以相互转换,比如给你个任务,要求12点执行,你看了一眼时间,发现现在是9点钟,那么你可以认为这个任务三个小时候执行。

那么我们换个说话,给你个任务让你3个小时后执行,你看了一眼现在是9点钟,那么你当然可以认为这个任务12点钟执行。

我们先来考虑一个简单的情况,你接到三个任务A、B、C(都转换成绝对时间),分别需要再3点钟,4点钟和9点钟执行,正当百思不得其解时,不经意间你瞅了一眼墙上的钟表,瞬间来了灵感,如醍醐灌顶,茅塞顿开:

那些惊艳的算法—时间轮算法

 

如上图中所示,我只需要把任务放到它需要被执行的时刻,然后等着时针转到这个时刻时,取出该时刻放置的任务,执行就可以了。 这就是时间轮算法最核心的思想了。 什么?时针怎么转? while-true-sleep 下面让我们一点一点增加复杂度。 ## 需要重复执行多次的任务 多数定时任务是需要重复执行,比如每天上午9点执行生成报表的任务。对于重复执行的任务,其实我们需要关心的只是下次执行时间,并不关心这个任务需要循环多少次,还是那每天上午9点的这个任务来说。 1. 比如现在是下午4点钟,我把这个任务加入到时间轮,并设定当时针转到明天上午九点(该任务下次执行的时间)时执行。 2. 时间来到了第二天上午九点,时间轮也转到了9点钟的位置,发现该位置有一个生成报表的任务,拿出来执行。 3. 同时时间轮发现这是一个循环执行的任务,于是把该任务重新放回到9点钟的位置。 4. 重复步骤2和步骤3。 如果哪一天这个任务不需要再执行了,那么直接通知时间轮,找到这个任务的位置删除掉就可以了。 由上面的过程我们可以看到,时间轮至少需要提供4个功能: 1. 加入任务 2. 执行任务 3. 删除任务 4. 沿着时间刻度前进 ## 同一时刻存在多个任务 上面说的是同一个时刻只有一个任务需要执行的情况,更通用的情况显然是同一时刻可能需要执行多个任务,比如每天上午九点除了生成报表之外,还需要执行发送邮件的任务,需要执行创建文件的任务,还需执行数据分析的任务等等,于是你刚才可能就比较好奇的时间轮的数据结构到现在可能更加好奇了,那我们先来说说时间轮的数据结构吧。 ### 时间轮的数据结构 首先,时钟可以用数组或者循环链表表示,这个每个时钟的刻度就是一个槽,槽用来存放该刻度需要执行的任务,如果有多个任务需要执行呢?每个槽里面放一个链表就可以了,就像下面图中这样:

那些惊艳的算法—时间轮算法

 

同一时刻存在多个任务时,只要把该刻度对应的链表全部遍历一遍,执行(扔到线程池中异步执行)其中的任务即可。

时间刻度不够用怎么办?

如果任务不只限定在一天之内呢?比如我有个任务,需要每周一上午九点执行,我还有另一个任务,需要每周三的上午九点执行。一种很容易想到的解决办法是:

增大时间轮的刻度

一天24个小时,一周168个小时,为了解决上面的问题,我可以把时间轮的刻度(槽)从12个增加到168个,比如现在是星期二上午10点钟,那么下周一上午九点就是时间轮的第9个刻度,这周三上午九点就是时间轮的第57个刻度,示意图如下:

那些惊艳的算法—时间轮算法

 

仔细思考一下,会发现这种设计方式存在几个缺陷:

时间刻度太多会导致时间轮走到的多数刻度没有任务执行,比如一个月就2个任务,我得移动720次,其中718次是无用功。

时间刻度太多会导致存储空间变大,利用率变低,比如一个月就2个任务,我得需要大小是720的数组,如果我的执行时间的粒度精确到秒,那就更恐怖了。

于是乎,聪明的你脑袋一转,想到另一个办法:

列表中的任务中添加round属性

这次我不增加时间轮的刻度了,刻度还是24个,现在有三个任务需要执行,

任务一每周二上午九点。

任务二每周四上午九点。

任务三每个月12号上午九点。

比如现在是9月11号星期二上午10点,时间轮转一圈是24小时,到任务一下次执行(下周二上午九点),需要时间轮转过6圈后,到第7圈的第9个刻度开始执行。

任务二下次执行第3圈的第9个刻度,任务三是第2圈的第9个刻度。

示意图如下:

那些惊艳的算法—时间轮算法

 

时间轮每移动到一个刻度时,遍历任务列表,把round值-1,然后取出所有round=0的任务执行。

这样做能解决时间轮刻度范围过大造成的空间浪费,但是却带来了另一个问题:时间轮每次都需要遍历任务列表,耗时增加,当时间轮刻度粒度很小(秒级甚至毫秒级),任务列表又特别长时,这种遍历的办法是不可接受的。

当然,对于大多数场景,这种方法还是适用的。

有没有既节省空间,又节省时间的办法呢?答案是有的,正如《Hashed and Hierarchical Timing Wheels》标题中提到的,有一种分层时间轮,可以解决做到既节省空间,又节省时间:

分层时间轮

分层时间轮是这样一种思想:

针对时间复杂度的问题:不做遍历计算round,凡是任务列表中的都应该是应该被执行的,直接全部取出来执行。

针对空间复杂度的问题:分层,每个时间粒度对应一个时间轮,多个时间轮之间进行级联协作。

第一点很好理解,第二点有必要举个例子来说明:

比如我有三个任务:

任务一每周二上午九点。

任务二每周四上午九点。

任务三每个月12号上午九点。

三个任务涉及到四个时间单位:小时、天、星期、月份。

拿任务三来说,任务三得到执行的前提是,时间刻度先得来到12号这一天,然后才需要关注其更细一级的时间单位:上午9点。

基于这个思想,我们可以设置三个时间轮:月轮、周轮、天轮。

月轮的时间刻度是天。

周轮的时间刻度是天。

天轮的时间刻度是小时。

初始添加任务时,任务一添加到天轮上,任务二添加到周轮上,任务三添加到月轮上。

三个时间轮以各自的时间刻度不停流转。

当周轮移动到刻度2(星期二)时,取出这个刻度下的任务,丢到天轮上,天轮接管该任务,到9点执行。

同理,当月轮移动到刻度12(12号)时,取出这个刻度下的任务,丢到天轮上,天轮接管该任务,到9点执行。

这样就可以做到既不浪费空间,又不浪费时间。

整体的示意图如下所示:

那些惊艳的算法—时间轮算法

 

时间轮的应用

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

至于采用round型的时间轮还是采用分层时间轮,看实际需要吧,时间复杂度和实现复杂度的取舍。



Tags:时间轮算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
从定时任务说起自然界中定时任务无处不在,太阳每天东升西落,候鸟的迁徙,树木的年轮,人们每天按时上班,每个月按时发工资、交房租,四季轮换,潮涨潮落,等等,从某种意义上说,都可以认为是...【详细内容】
2021-04-22  Tags: 时间轮算法  点击:(361)  评论:(0)  加入收藏
最近看 Kafka 看到了时间轮算法,记得以前看 Netty 也看到过这玩意,没太过关注。今天就来看看时间轮到底是什么东西。为什么要用时间轮算法来实现延迟操作?延时操作 Java 不是...【详细内容】
2020-08-07  Tags: 时间轮算法  点击:(62)  评论:(0)  加入收藏
大家好,我是yes。最近看 Kafka 看到了时间轮算法,记得以前看 Netty 也看到过这玩意,没太过关注。今天就来看看时间轮到底是什么东西。为什么要用时间轮算法来实现延迟操作?延时...【详细内容】
2020-08-04  Tags: 时间轮算法  点击:(59)  评论:(0)  加入收藏
大家好,我是yes。最近看 Kafka 看到了时间轮算法,记得以前看 Netty 也看到过这玩意,没太过关注。今天就来看看时间轮到底是什么东西。为什么要用时间轮算法来实现延迟操作?延时...【详细内容】
2020-08-04  Tags: 时间轮算法  点击:(61)  评论:(0)  加入收藏
前言我在 2. SOFAJRaft源码分析—JRaft的定时任务调度器是怎么做的? 这篇文章里已经讲解过时间轮算法在JRaft中是怎么应用的,但是我感觉我并没有讲解清楚这个东西,导致看...【详细内容】
2020-03-01  Tags: 时间轮算法  点击:(66)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(9)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(19)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(13)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯·奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(37)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条