C++ 公共组件-定时器(time wheel)

一. 定时器实现

我们知道定时器的实现方式有很多种,最为常见的就数时间堆和时间轮了. 这里介绍时间轮实现的定时器。
时间轮总体来说,对于频繁的插入和删除来说,时间轮的效率较为高些.

二、时间轮算法

1. 单级时间轮算法

在这里插入图片描述
如上图就是一个简单的时间轮。类比于时钟的秒针表盘,秒针表盘共 60 秒的刻度,以恒定速度每秒 1 刻度进行读秒。时间轮也是一样,该时间轮共有 N 个 tick 刻度,以恒定速度每次走 1 个 tick 单位时间。每个 tick 对应的是一个双向循环链表,该链表元素为计时器。
处理定时器的过程 :如图,指针指向 1,说明 tick 1 所在的链表中的计时器全部到期,遍历该链表,执行到期的计时器的回调函数。再过 1 tick 时间,表盘指针指向 2,tick 2 所在的链表中的计时器全部到期,然后遍历链表处理到期的计时器。

2. 多级时间轮算法

1) 介绍

还以秒针表盘为例,秒针表盘 60s 需要 60 个刻度,如果是 1h 呢?难道需要 3600 个刻度吗?不是这样的,时钟有 3 级表盘,秒针、分针、时针,它们的粒度分别是 1s、1min、1h。
同样的,表示一个 32bits 以毫秒为单位的时间,粒度为 1ms,如果采用 1 级时间轮算法,则需要 2^32 个 tick,这对于内存空间的消耗非常大。当然,可以降低定时器精度,使每个 tick 表示的时间长一点,但这样的代价将是定时器的精度大打折扣。
linux 内核中的多级时间轮算法采用 5 级时间轮,每级时间轮的粒度分别为:1ms、256ms、25664ms、2566464ms、256646464ms。它们每级时间轮 tick 刻度数量分别为 256(低 8bits)、64(次 6bits)、64(次 6bits)、64(次 6bits)、64(高 6bits)。

2) 处理过程
  1. 对于一个 32bits 以毫秒为单位的时间 t。tick 取 t 的低 8bits。如果 tick 不为 0,执行步骤 6;如果 tick 为 0,执行步骤 2
  2. tick 取 t 的次 6 bits,如果 tick 不为 0,取出 2 级时间轮该 tick 的双向循环链表,然后遍历该链表的定时器,根据到期时间来判断将定时器插入到 1 级时间轮还是 2 级时间轮,执行步骤 6。如果 tick 为 0,执行步骤3
  3. tick 取 t 的次 6 bits,如果 tick 不为 0,取出 3 级时间轮该 tick 的双向循环链表,然后遍历该链表的定时器,根据到期时间来判断将定时器插入到 1 级、2 级、3 级时间轮,执行步骤 6。如果 tick 为 0,执行步骤4
  4. tick 取 t 的次 6 bits,如果 tick 不为 0,取出 4 级时间轮该 tick 的双向循环链表,然后遍历该链表的定时器,根据到期时间来判断将定时器插入到 1 级、2 级、3 级、4 级时间轮,执行步骤 6。如果 tick 为 0,执行步骤5
  5. tick 取 t 的高 6 bits,如果 tick 不为 0,取出 5 级时间轮该 tick 的双向循环链表,遍历,根据到期时间来判断将定时器插入到 1 级、2 级、3 级、4 级、5 级时间轮,执行步骤 6
  6. 遍历 1 级时间轮中该 tick 的双向循环链表,执行这些到期定时器的回调函数
3)特点
  • 可添加大量计时器
  • 支持从系统启动到 2^32ms 的时间
  • 时间精度为毫秒
  • 可添加 One-Shot Timer(一次性的计时器),也可添加 Repeating Timer(带有首次触发时间和再次触发时间间隔的计时器)
  • 采用多级时间轮算法,节省内存
  • 定时器的增删执行时间复杂度均为 O(1)
  • 时间轮的运行需要 1 个线程

3. 代码实现

多级时间轮定时器

三、参考网址

参考网址1
参考网址2

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值