TimingWheel 令人拍案叫绝的设计
常规时间轮
都知道时钟有指针、刻度、每刻度表示的时长等属性,Netty时间轮的设计也差不多,只是时钟的指针有时、分、秒,而Netty只用了一个指针。那么Netty是如何把定时任务加入时间轮的呢?下面先看一幅时间轮的构造图
当指针指向某一刻度时,它会把此刻度中的所有task任务一一取出并运行
那么问题来了:
- 时间轮的指针走一轮是多久?
- 时间轮是采用什么容器存储这些task的?
- 定时任务的运行时间若晚于指针走一轮的终点,则此时此任务该放在哪个刻度?
- 刻度的间隔时间标注为tickDuration,同时将时间轮一轮的刻度总数标注为wheelLen,两者都是时间轮的属性,可以通过构造方法由使用者传入,这样就可以得到时间轮指针走一轮的时长=tickDuration*wheelLen。
- 当指针运行到某一刻度时,需要把映射在此刻度上所有的任务都取出来,而刻度总数在时间轮初始化后就固定了。因此与Map相似,采用数组标识wheel[]加链表的方式来存储这些task,数组的大小固定为图7-1中的N,刻度的编号就是wheel[]的下标。
- 每个时间轮启动都会记录其启动时间,同时,每个定时任务都有其确定的执行时间,用这个执行时间减去时间轮的启动时间,再除以刻度的持续时长,就能获取这个定时任务需要指针走过多少刻度才运行,标注为calculated。时间轮本身记录了当前指针已经走过了多少刻度,标注为tick。通过calculated、tick、时间轮刻度总数wheelLen来计算定时任务在哪一刻度执行(此刻度标注为stopIndex)
那么问题又来了,如果设置的总刻度*刻度间隔时间 < 新任务的执行时间怎么办?
在“时间轮”的算法中,定时器检测进程只需要判断“时间轮”数组现在所指向的索引里的链表为不为空(即里面有没有超时的定时器),如果为空则不执行任何操作,如果不为空则对于这个数组元素链表里的所有定时器执行定时器超时进程(定时器的组件3)。而每当“时间轮”的周期数加 1 的时候,系统都会遍历一遍溢出列表里的定时器是否满足当前周期数,如果满足的话,则将这个位置的溢出列表全部移到“时间轮”相对应的索引位置中。注意为了溢出链表的判断复杂度比较低,溢出链表的维护也是有序的
变种时间轮
基本的“时间轮”插入操作因为维护了一个溢出列表导致定时器的插入操作无法做到 O(1) 的时间复杂度,所以为了 O(1) 时间复杂度的插入操作,一种变种的“时间轮”算法就被提出了。
在这个变种的“时间轮”算法里,我们加了一个 MaxInterval 的限制,这个 MaxInterval 其实也就是我们定义出的“时间轮”数组N的大小。假设“时间轮”数组的大小为 N,对于任何需要新加入的定时器,如果超时(绝对)时间小于 N 的话,则被允许加入到“时间轮”中,否则将不被允许加入。
注意,什么叫超时绝对时间? 还是以上面的例子为例,当前时间是 2T, 然后超时T的定时器想加进来,则绝对超时时间就是 3T,这个3T 是相对于当前时间轮周期的起点而言的,这个3T 就是超时绝对时间,只有3T <N, 该定时器才能被加入时间轮,否则拒绝其加入.
这种“时间轮”变种算法,执行定时器检测进程还有插入和删除定时器的操作时间复杂度都只有 O(1)。
分层时间轮
我们可以使用三个“时间轮”来表示不同颗粒度的时间,分别是小时“时间轮”、分钟“时间轮”和秒“时间轮”,可以称小时“时间轮”为分钟“时间轮”的上一层“时间轮”,秒“时间轮”为分钟“时间轮”的下一层“时间轮”。分层“时间轮”会维护一个“现在时间”
每层“时间轮”都需要各自维护一个当前索引来表示“现在时间”。例如,分层“时间轮”的“现在时间”是22h:20min:30s,它的结构图如下图所示:
当每次有新的定时器需要插入进分层“时间轮”的时候,将根据分层“时间轮”的“现在时间”算出一个超时的绝对时间。例如,分层“时间轮”的“现在时间”是 21h:20min:30s,而当我们要插入的新定时器超时时间为 50 分钟 10 秒时,这个超时的绝对时间则为 22h:10min:40s。
我们需要先判断最高层的时间是否一致,如果不一致的话则算出时间差,然后插入定时器到对应层的“时间轮”中,如果一致,则到下一层中的时间中计算,如此类推。在上面的例子中,最高层的时间小时相差了 22(22h:10min:40s的小时数)-21(21h:20min:30s的小时数) = 1 小时,所以需要将定时器插入到小时“时间轮”中的 (1 + 21) % 24 = 22这个索引中,定时器列表里还需要保存下层“时间轮”所剩余的时间 10min:40s,如下图所示, 这就完成了该定时器的插入:
每经过一秒钟,秒“时间轮”的索引都会加 1,并且执行定时器检测进程。定时器检测进程需要判断当前元素里的定时器列表是否为空,如果为空则不执行任何操作,如果不为空则对于这个数组元素列表里的所有定时器执行定时器超时进程。需要注意的是,定时器检测进程只会针对最下层的“时间轮”执行(原因你看完下面的举例就明白了)。
如果秒“时间轮”的索引到达 60 之后会将其归零,并将上一层的“时间轮”索引加 1,同时判断上一层的“时间轮”索引里的列表是否为空,如果不为空,则按照之前描述的算法将定时器加入到下一层“时间轮”中去,如此类推。
举个例子吧~ 在经过一段时间之后,上面的分层“时间轮”会到达以下的一个状态(即当前时间变成 22:00:00):
这时候上层“时间轮”索引里的列表不为空(挂着一个10min:40s),将这个定时器加入的索引为 10 的分钟“时间轮”中,并且保存下层“时间轮”所剩余的时间 40s,如下图所示:
如此类推,在经过 10 分钟之后(即当前时间来到 22:10:00),分层“时间轮”会到达以下的一个状态
同样的,我们将这个定时器插入到秒“时间轮”中,如下图所示:
这个时候,再经过 40 秒,秒“时间轮”的索引将会指向一个元素,里面有着非空的定时器列表,然后执行定时器超时进程并将定时器列表里所有的定时器删除。这就是为什么前面说定时器检测进程只会针对最下层的“时间轮”执行
我们可以看到,采用了分层“时间轮”算法之后,我们只需要维护一个大小为 24(小时) + 60(分钟) + 60(秒) = 144 的数组而同时保持着执行定时器检测进程还有插入和删除定时器的操作时间复杂度都只有 O(1)
TimingWheel 令人拍案叫绝的设计相关推荐
- 深入理解 python 虚拟机:令人拍案叫绝的字节码设计
深入理解 python 虚拟机:令人拍案叫绝的字节码设计 在本篇文章当中主要给大家介绍 cpython 虚拟机对于字节码的设计以及在调试过程当中一个比较重要的字段 co_lnotab 的设计原理! p ...
- 令人拍案叫绝的Wasserstein GAN
雷锋网按:本文作者郑华滨,原载于知乎.雷锋网已获转载授权. 在GAN的相关研究如火如荼甚至可以说是泛滥的今天,一篇新鲜出炉的arXiv论文<Wassertein GAN>却在Reddit的 ...
- 令人拍案叫绝的 Wasserstein GAN,彻底解决GAN训练不稳定问题
[新智元导读] 本文详细解析了最近在 reddit 的 Machine Learning 版引起热烈讨论的一篇论文Wassertein GAN,该论文提出的 WGAN 相比原始 GAN 的算法实现流程 ...
- [转载]--令人拍案叫绝的Wasserstein GAN
文章转载自: https://zhuanlan.zhihu.com/p/25071913 令人拍案叫绝的Wasserstein GAN 郑华滨 · 2 天前 在GAN的相关研究如火如荼甚至可以说是泛滥 ...
- 设计师喜欢收集各种各样的笔刷来喽,不必倾家倾产就能像创造出令人惊叹的设计。
一组最好的Photoshop笔刷,让您不必倾家倾产就能像专业人士一样创造出令人惊叹的设计. 我们知道设计师喜欢收集各种各样的刷子. 对于创建各种类型的设计非常有用,包括从绘画到绘画,上色,纹理,肌理等 ...
- 深度有趣 | 16 令人拍案叫绝的WGAN
简介 在DCGAN的基础上,介绍WGAN的原理和实现,并在LFW和CelebA两个数据集上进一步实践 问题 GAN一直面临以下问题和挑战 训练困难,需要精心设计模型结构,并小心协调G和D的训练程度 G ...
- 一种令人拍案叫绝的 ChatGPT 攻击手段!
公众号关注 "GitHubDaily" 设为 "星标",每天带你逛 GitHub! 最近看到一个非常巧妙的 ChatGPT 攻击手段,跟大家分享一下,也算是做个 ...
- 有哪些令人拍案叫绝的算法?
介绍一个简单易懂然后又让你拍案叫绝的算法! 这个算法的代码量很少,却很惊艳. 它就是传说中的 洗牌算法 ! 小技巧:看到一个好答案,想点赞又嫌麻烦,可以双击屏幕自动点,既能鼓舞作者,又能很方便自己下次 ...
- 1个字,绝! -- CNN中十大令人拍案叫绝的操作
前言 近十年是深度学习飞速发展的十年,自LeNet.AlexNet发展至今,通道注意力.空间注意力.生成对抗网络等技术层出不穷,最近大火的Transformer技术也在屠杀各种深度学习比赛的榜单,经过 ...
最新文章
- BCH区块链上的预言机项目——Oracles
- 关于C++对象模型的一点理解(2)
- struts2.0和struts1.x的区别
- Redis 的 4 大法宝,2018 必学中间件
- 泸西一中2021高考成绩查询,云南红河州四所好高中,红河州一中一本率领先,建水一中不容小觑...
- 鸿蒙的应用列表,图解鸿蒙列表组件ListContainer
- VS2017安装方法
- 快速入门(完整):Python实例100个(基于最新Python3.7版本)
- 使用 HTML 和 CSS 创建响应式猫猫图片库
- STM32 FreeRTOS系列教程(一)FreeRTOS简介
- 软件工程毕业论文mysql英文翻译_软件工程毕业论文文献翻译中英文对照
- 论文引用内容计算重复率吗?
- 六、定语从句和关系代词
- android10怎么截屏,安卓手机怎么截图?安卓手机截图方法大全
- 云班课python测试答案_智慧职教云课堂APPPython程序设计题目答案
- C语言实现函数确定最大最小值
- ubuntu20.04如何录制屏幕
- socket error 10054错误出现的原因以及解决办法,全网最全没有之一
- xbox sdk_因此,您只是获得了Xbox Xbox。 怎么办?
- js动态添加,jq,ajax
热门文章
- ssm框架整合的crud项目详细步骤
- 工作站启动不起来的解决方案
- The security strength of SHA-1 digest algorithm is not sufficient for this key size
- 38个优秀博客站点推荐
- 一文读懂「用户行为数据」的采集、分析和应用
- 《手机拍照与视频》那点事
- 未来互联网时代的制造业
- bzoj2215[POI2011]Conspiracy
- R语言 Rstudio 安装 包 报错installation of package ‘*’ had non-zero exit status
- SEO Sitemap优化