时间轮算法 2

时间轮的功能

  • 干什么用的:
    时间轮是比常用的一种时间调度器算法

  • 场景
    如果你要实现一个延时执行的方法会如何做?
    使用一个定时器Ticker,到时间执行方法, 这种方法是没有问题的.

那现在需求升级,需要实现一个可以随时添加,更改,删除延时任务怎么做?

这就是下面要介绍的时间轮算法.

时间轮算法的原理

基本原理:

将时间分成一个个时间格,每个时间格上面存放改时间刻度要执行的方法,每个方法都加到对应的时间格上面(比如 1s 一个时间格,一共 60 个时间格,你添加一个 20s 后的延时任务,那么任务将会挂到当前时间格位置再往后的 20 个时间格上面,时间调度器会让时间格下标每一秒向后移动一位,并扫描执行挂在那个时间格上面的方法)

  • 那么问题来了: 时间是无限的,你设置的时间格是有限的,时间跨度是有限的;
  • 比如你使用的 1s*60 的时间轮,如果一个 100s 的延时任务过来,超过时间轮的跨度如何处理?
多层结构

使用多层时间轮的结构,上层时间轮 的时间格存放指向下层时间格的指针,那么上层时间格的时间跨度就是下层时间轮的时间跨度的总和,运行的逻辑就是下层转一圈,上层转一格.

简单理解就是一个🕙,秒针是最低的时间轮,秒针转一圈,上层时间轮分钟的指针移动一格,分钟的时间轮转一圈,小时的时间轮移动一格
这样使用多层时间轮的方式就可以解决时间超过时间轮跨度的问题,

  • 假设是 1s*60 的时间轮,加入一个 100s 的延时任务,先检查第一个时间轮超过时间跨度 60s,再使用上层时间轮 1min *60,没有超过时间刻度,刚好在第一格(从 0 开始算),方法先加到第二层的时间格上;

  • 随着时间推进,第一层运行完一圈(60s),开始第二层指针向后移动一格取出第二层第1 格的延时任务加到第一层上(使用取余的方式 )刚好在 40 格的位置,当第一层的第二圈(1-2min)运行到第 40 格,去除对应的任务执行就行了,不需要再做额外的判断.

圈数特性

第二个方案就是给任务加上圈数的特性.就是记录任务在第几圈执行

  • 假如我的时间轮是 1s*60 的时间跨度,现在要加入 100s 的延时任务,超过了时间跨度,那么就记录他超过了多少圈,发现超过了一圈,圈数记录为 1,然后加到(100%60 取余)为 40 的时间格上面,
  • 运行逻辑: 当时间运行到 40 的时间格 时先检查任务是否当圈执行(圈数为 0)如果是就立即执行,如果不是就圈数减一
方法的优缺点:
层级方案:

优点: 每个时间格是唯一的 ,只挂载当前时间要执行的任务,不需要判断圈数
缺点: 随着运行时间的加长,时间格使用的空间将越来越多(一层层的开辟新的空间)

圈数特性

优点: 一个时间轮重复使用,没有多余的空间需要开辟
缺点: 每个时间格可能挂载较多延时任务(超过时间跨度的任务),每次都要判断执行.

时间轮的更改与删除

上面主要是增加延时任务与运行的逻辑,那么我们如何更改与删除一个延时任务?难道要扫描整个时间轮找到任务删除?

肯定不能扫描整个时间轮,那样太消耗时间了

使用map去记录在时间轮中的位置
  • 如何做?
    我们运行时间轮其实就是扫描时间格挂载的任务并执行,无论是使用多层结构还是利用圈数特性,这个特质是不变的
    我们需要一个 key 去标记每一个任务,相同的 key 认为是同一个任务,当我们加入的时候将加入的任务链表的指针加入到map 中,key 就是任务的 key,val 存放对应时间格任务链表的指针与任务在链表中的节点
    我们可以使用 key快速找到对应的时间格位置执行更改或者删除任务.

参考:
https://cloud.tencent.com/developer/article/2356003
https://juejin.cn/post/7083795682313633822
https://www.luozhiyun.com/archives/444

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值