来自:架构之美

上一篇热文《构建企业级业务高可用的延时消息中台》引起了大家的讨论,评论里讨论除了时间轮算法外的其他高性能算法实现延迟消息的定时器。这一篇文章系统的梳理主流定时器算法实现的差异以及应用地方。

1. 定时器介绍

程序里的定时器主要实现的功能是在未来的某个时间点执行相应的逻辑。在定时器模型中,一般有如下几个定义。

interval:间隔时间,即定时器需要在interval时间后执行
StartTimer:添加一个定时器任务
StopTimer:结束一个定时器任务
PerTickBookkeeping: 检查定时器系统中,是否有定时器实例已经到期,相当于定义了最小时间粒度。

常见的实现方法有如下几种:

链表
排序链表
最小堆
时间轮

接下来我们一起看下这些方法的具体实现原理。

2. 定时器实现方法

2.1 链表实现


链表的实现方法比较粗糙。链表用于存储所有的定时器,每个定时器都含有interval 和 elapse 两个时间参数,elapse表示当前被tickTimer了多少次。当elapse 和interval相等时,表示定时器到期。

在此方案中,添加定时器就是在链表的末尾新增一个节点,时间复杂度是 O(1)。

如果想要删除一个定时器的话,我们需要遍历链表找到对应的定时器,时间复杂度是O(n)。

此方案下,每隔elapse时间,系统调用信号进行超时检查,即PerTickBookkeeping。每次PerTickBookkeeping需要对链表所有定时器进行 elapse++,因此可以看出PerTickBookkeeping的时间复杂度是O(N)。

可以看出此方案过于粗暴,所以使用场景极少。

2.2 排序双向链表实现


排序双向链表是在链表实现上的优化。优化思路是降低时间复杂度。

首先,每次PerTickBookkeeping需要自增所有定时器的elapse变量,如果我们将interval变为绝对时间,那么我们只需要比较当前时间和interval时间是否相等,减少了对每个定时器的操作。

如果不需要对每个定时器进行操作,我们将定时器进行排序,那么每次PerTickBookkeeping都只需要判断第一个定时器,时间复杂度为O(1)。

相应的,为了维持链表顺序,每次新增定时器需要进行链表排序时间复杂度为 O(N)。

每次删除定时器时,由于会持有自己节点的引用,所以不需要查找其在链表中所在的位置,所以时间复杂度为O(1),双向链表的好处。

图1 双向链表实现示意图

2.3 时间轮实现


相信上一篇文章《构建企业级业务高可用的延时消息中台》我们已经对时间轮有了很深刻的了解。时间轮示意图如下:

图2 时间轮

时间轮的数据结构是数组 + 链表。

他的时间轮为数组,新增和删除一个任务,时间复杂度都是O(1)。

PerTickBookkeeping每次转动一格,时间复杂度也是O(1)。

2.4 最小堆实现


最小堆是堆的一种, (堆是一种二叉树), 指的是堆中任何一个父节点都小于子节点, 子节点顺序不作要求。

二叉排序树(BST)指的是: 左子树节点小于父节点, 右子树节点大于父节点, 对所有节点适用

图3 最小堆

树的基本操作是插入节点和删除节点。对最小堆而言,为了将一个元素X插入最小堆,我们可以在树的下一个空闲位置创建一个空穴。如果X可以放在空穴中而不被破坏堆的序,则插入完成。否则就执行上滤操作,即交换空穴和它的父节点上的元素。不断执行上述过程,直到X可以被放入空穴,则插入操作完成。

因此我们可以知道最小堆的插入时间复杂度是O(lgN)。

最小堆的删除和插入逻辑基本类似,如果不做优化,时间复杂度也是O(lgN),但是实际实现方案上,做了延迟删除操作,时间复杂度为O(1)。

延迟删除即设置定时器的执行回调函数为空,每次最小堆超时,将触发pop_heap,pop会重新调整最小堆,最终删除的定时器将调整到堆顶,但是回调函数不处理。

可以看到PerTickBookkeeping只处理堆顶定时器,时间复杂度O(1)。

最小堆可以使用数组来进行表示,数组中,当前下标n的左子节点为2N + 1,当前下标n的右子节点小标为2N + 2。

图4 最小堆的数组表示

3. 定时器不同实现对比

3.1 时间复杂度对比


图5 不同实现时间复杂度

从上面的介绍来看,时间轮的时间复杂度最小、性能最好。

3.2 使用场景来看

在任务量小的场景下:最小堆实现,可以根据堆顶设置超时时间,数组存储结构,节省内存消耗,使用最小堆可以得到比较好的效果。而时间轮定时器,由于需要维护一个线程用来拨动指针,且需要开辟一个bucket数组,消耗内存大,使用时间轮会较为浪费资源。

在任务量大的场景下:最小堆的插入复杂度是O(lgN), 相比时间轮O(1) 会造成性能下降。更适合使用时间轮实现。

在业界,服务治理的心跳检测等功能需要维护大量的链接心跳,因此时间轮是首选。

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

长按订阅更多精彩▼如有收获,点个在看,诚挚感谢

一文完全理解定时器实现技术相关推荐

  1. 智能文档理解:通用文档预训练模型

    预训练模型到底是什么,它是如何被应用在产品里,未来又有哪些机会和挑战? 预训练模型把迁移学习很好地用起来了,让我们感到眼前一亮.这和小孩子读书一样,一开始语文.数学.化学都学,读书.网上游戏等,在脑子 ...

  2. 赋能RPA时代,微软发布通用文档理解预训练模型LayoutLM

    来源:微软研究院AI头条 本文约3900字,建议阅读10+分钟 有效利用文档结构信息和视觉结构信息,显著提高模型准确率. 标签:自然语言处理 [ 导读 ]近年大热的机器人流程自动化(Robotic P ...

  3. 硬核科普:一文看懂人脸识别技术流程

    小编是个天生懒惰的人,同时又是个急性子,这样的人最享受被科技服务的乐趣. 举个例子,十多年前大家还在普遍用现金的时代,小编在商店买东西排队结账,每当看到收银员找零时手忙脚乱的样子就会心急如焚,只恨不能 ...

  4. 短视频内容理解与生成技术在美团的创新实践

    点击上方"LiveVideoStack"关注我们 美团围绕丰富的本地生活服务电商场景,积累了海量视频数据.如何通过计算机视觉技术用相关数据,为用户和商家提供更好的服务,是一项重要的 ...

  5. MSRA-万字综述 直击多模态文档理解

    文 | 付奶茶 随着最近几年多模态大火的,越来越多的任务都被推陈出新为多模态版本.譬如,传统对话任务,推出了考虑视觉信息的多模态数据集:事件抽取,也推出视频形式的多模态版本:就连 grammar in ...

  6. 别再搞纯文本了!多模文档理解更被时代需要!

    文 | Ryan 都已经2021年了,互联网已经今非昔比,20年前纯文本的日子已经一去不复返,文字已经满足不了网页.文章的需求,绝大部分都会有着精心设计的表格.图片,甚至视频.PDF文档这种富文本格式 ...

  7. 谷歌发布端到端AI平台,还有用于视频和表格的AutoML、文档理解API等多款工具

    谷歌又有了大动作.在大洋彼岸的谷歌Cloud Next conference大会上,谷歌一口气发布了多款AI新品和工具,主要包括: 端到端的AI平台 用于处理视频和表格数据的AutoML Tables ...

  8. 文档理解最新技术介绍 | DAS 2020 Keynote Speech

    DAS 2020 (Document Analysis System,文档分析系统研讨会) 于 7月26-29日在武汉召开,本次研讨会中有不少精彩的内容,昨天向大家推荐了来自华南理工大学金连文老师和 ...

  9. 论文解读丨LayoutLM: 面向文档理解的文本与版面预训练

    摘要:LayoutLM模型利用大规模无标注文档数据集进行文本与版面的联合预训练,在多个下游的文档理解任务上取得了领先的结果. 本文分享自华为云社区<论文解读系列二十五:LayoutLM: 面向文 ...

最新文章

  1. 程序员的自我修养--链接、装载与库笔记:系统调用与API
  2. RDKit | RDKit(2019.09)新增相似性图函数
  3. zuul 动态路由mysql_zuul 动态路由 - typistw的个人空间 - OSCHINA - 中文开源技术交流社区...
  4. WINDOWS与LINUX下的DNS轮询配置
  5. 字典数(前缀树)的实现
  6. srt编辑的文件在linux显示乱码,解决看本地视频srt字幕乱码问题教程-srt文件
  7. android 添加随意拖动的桌面悬浮窗口,android 添加随意拖动的桌面悬浮窗口
  8. JavaScript技巧[转载]
  9. 小米某员工向供应商索要大额好处费 已被公安拘捕
  10. 车仪表台上的装饰_@云浮车主:车内装饰品摆放不当将被处罚
  11. JS内存泄漏实例解析
  12. 11.go 环境变量
  13. element-plus日期选择器 value-format出错
  14. SQL 日期交差判断
  15. 鸿蒙系统如何添加桌面小程序,微信Windows版更新至3.0:批量管理联系人,小程序可添加至桌面...
  16. linux native是啥分区,Linux native是什么意思
  17. VSS(Visual SourceSafe)使用方法
  18. 使用python脚本和crontab在阿里云实现优矿自动签到
  19. C# DataGridView 打印代码
  20. 2022-2027年中国气体灭火设备市场规模现状及投资规划建议报告

热门文章

  1. 手写体数字识别(理解起来更简单一点)
  2. PTA基础编程题目集-6-13 折半查找
  3. python程序更新实现_Python 软件热更新
  4. 2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)
  5. 【学习笔记】超简单的多项式开方
  6. L - Subway POJ - 2502
  7. php语言出现弹框 再提交怎么写,jquery/php和多语言确认/警报框
  8. socket心跳机制图片_socket心跳包机制
  9. input框选中时如何不出灰框_如何建立学习目标:这个SMART原则,你要了解,家长看懂教给孩子...
  10. postman设置Cookie上行参数访问接口