范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

非常详细通过时间轮(TimingWheel)实现延时队列的原理指南

  时间轮的介绍
  时间轮(TimeWheel)是一种实现延迟功能(定时器)的精妙的高级算法,其算法应用范围非常广泛,在Java开发过程中常用的Dubbo、Netty、Akka、Quartz、ZooKeeper 、Kafka等各种框架中,各种操作系统的定时任务crontab调度都有用到,甚至Linux内核中都有用到,不夸张的是几乎所有和时间任务调度都采用了时间轮的思想。时间轮的作用高效处理批量任务
  时间轮可以高效的利用线程资源来进行批量化调度,把大批量的调度任务全部都绑定时间轮上,通过时间轮进行所有任务的管理,触发以及运行。降低时间复杂度
  时间轮算法可以将插入和删除操作的时间复杂度都降为O(1),在大规模问题下还能够达到非常好的运行效果。高效管理延时队列
  能够高效地管理各种延时任务,周期任务,通知任务等,相比于JDK自带的Timer、DelayQueue + ScheduledThreadPool来说,时间轮算法是一种非常高效的调度模型。缺点:时间精确度的问题
  时间轮调度器的时间的精度可能不是很高,对于精度要求特别高的调度任务可能不太适合。因为时间轮算法的精度取决于时间段"指针"单元的最小粒度大小,比如时间轮的格子是一秒跳一次,那么调度精度小于一秒的任务就无法被时间轮所调度。
  精度问题我们可以考虑后面提出的优化方案:多级时间轮。时间轮的使用场景调度模型,时间轮是为解决高效调度任务而产生的调度模型。例如,周期任务。数据结构,通常由hash table和链表实现的数据结构。延时任务、周期性任务应用场景主要在延迟大规模的延时任务、周期性的定时任务等。通知任务等等。时间轮的实现方案
  为了充分发挥时间轮算法的效果和优势,我们要从基础上去分析和优化时间轮算法对比定时任务、任务队列模式的运作基底。减少线程分配
  时间轮是一种高效来利用线程资源来进行批量化调度的一种调度模型,把大批量的调度任务全部都绑定到同一个的调度器上面,使用这一个调度器(线程)来进行所有任务的管理(manager),触发(trigger)以及运行(runnable)。CPU的负载和资源浪费减少
  承接上面减少线程分配,最后可以使得当我们需要进行大量的调度任务或者延时任务,可以大大减少线程的分配,如果按照任务调度模式,每个任务都使用自己的调度器来管理任务的生命周期的话,可能会进行分配很多线程,从而会消耗CPU的资源并且很低效。
  注意:问题就是如果这个调度器的调度线程出现了问题,会导致整体全局崩溃。延时任务或定时任务实现原理
  如何实现定时任务 / 延时任务,定时的任务调度分两种:延时任务:一段时间后执行,即:相对时间。定时任务:指定某个确定的时间执行,即:绝对时间。
  对于延时任务和定时任务两者之间是可以相互转换的,例如当前时间是12点,定时在5分钟之后执行,其实绝对时间就是:12:05,定时在12:05执行,相对时间就是5分钟之后执行。时间轮功能设计
  时间轮实现定时/延时任务队列,最终需要向上层提供如下接口:添加定时/延时任务删除定时/延时任务执行定时/延时任务时间轮的数据结构时间轮(HashedWheelTimer)是存储定时任务的环形队列,底层采用数组实现,数组中的每个元素可以存放个定时任务列表(HashedWheelBucket)。HashedWheelBucket是环形的双向链表,链表中的每一项表示的都是定时任务项(HashedWheelTimeout),其中封装了真正的定时任务(TimerTask)。单时间轮基本逻辑模型
  时间轮算法是:不再任务队列作为数据结构,轮询线程不再负责遍历所有任务,而是仅仅遍历时间刻度。时间轮算法好比指针不断在时钟上旋转、遍历,如果一个发现某一时刻上有任务(任务队列),那么就会将任务队列上的所有任务都执行一遍。
  时间轮由多个时间格组成,每个时间格代表当前时间轮的基本时间跨度(tickDuration),时间轮的时间格个数是固定的。
  如上图中相邻bucket到期时间的间隔为bucket=1s,从0s开始计时,1s时到期的定时任务挂在bucket=1下,2s时到期的定时任务挂在bucket=2下,当检查到时间过去了1s时,bucket=1下所有节点执行超时动作,当时间到了2s时,bucket=2下所有节点执行超时动作等等。
  如上图的时间轮通过数组实现,可以很方便地通过下标定位到定时任务链路,因此,添加、删除、执行定时任务的时间复杂度为O(1)。时间轮数据结构模型pointer : 指针,随着时间的推移,指针不停地向前移动。bucket : 时间轮由bucket组成,如上图,有12个bucket。每个bucket都挂载了未来要到期的节点(即: 定时任务/延时任务)。slot : 指相邻两个bucket的时间间隔。tickDuration:slot的单位,1s(1HZ),如上图,总共12个bucket,那么两个相邻的bucket的时间间隔就是一秒。
  时间轮使用一个表盘指针(pointer),用来表示时间轮当前指针跳动的次数,可以用tickDuration * (pointer + 1)来表示下一次到期的任务,需要处理此时间格所对应的 TimeWheel中的所有任务。时间轮处理逻辑计算延时时间存储
  时间轮在启动的时候会记录一下当前启动的时间赋值给startTime。时间轮在添加任务的时候首先会计算延迟时间(delayTime),比如一个任务的延迟时间为24ms,那么会将当前的时间(currentTime)+24ms-时间轮启动时的时间(startTime)。然后将任务封装成TimeWheelElement加入到bucket队列中。TimeWheelElement的总共延迟的次数:将每个任务的延迟时间(delayTime)/ tickDuration计算出pointer需要总共跳动的次数以及计算出该任务需要放置到时间轮(wheel)的槽位,然后加入到槽位链表最后将任务放置到时间轮wheel中。读取延时数据任务队列
  时间轮在运行的时候会将bucket队列中存放的TimeWheelElement任务取出来进行遍历,从而进行执行对应的任务体系机制。计算出当前时针走到的槽位的位置,并取出槽位中的链表数据,防止万一,还可以再delayTime和当前的时间做对比,运行过期的数据。单时间轮的问题和弊端显而易见,时间轮算法解决了遍历效率低的问题。(现在,即使有 10k 个任务,轮询线程也不必每轮遍历10k个任务,而仅仅需要遍历24个时间刻度)。时间轮算法中,轮询线程遍历到某一个时间刻度后,总是执行对应刻度上任务队列中的所有任务(通常是将任务扔给异步线程池来处理),而不再需要遍历检查所有任务的时间戳是否达到要求。内存和资源的消耗巨大
  但这种单时间轮是存在限制的,只能设置定时任务到期时间在12s内的,这显然是无法满足实际的业务需求的。当然也可以通过扩充bucket的范围来实现。例如,将bucket设置成 2^32个,但是这样会带来巨大的内存消耗,显然需要优化改进。轮询线程仍然还会慢慢的出现遍历效率低问题
  当时间刻度增多,而任务数较少时,轮询线程的遍历效率会下降,例如,如果只有 50 个时间刻度上有任务,但却需要遍历 1440 个时间刻度。这违背了我们提出时间轮算法的初衷:解决遍历轮询线程遍历效率低的问题。浪费内存空间问题
  在时间刻度密集,任务数少的情况下,大部分时间刻度所占用的内存空间是没有任何意义的。如果要将时间精度设为秒,那么整个时间轮将需要 86400 个单位的时间刻度,此时时间轮算法的遍历线程将遇到更大的运行效率低的问题。轮数时间轮基本逻辑模型
  时间轮的时间刻度随着时间精度而增加并不是一个好的问题解决思路,所以计划将时间轮的精度设置为秒,时间刻度个数固定为60。每一个任务拥有一个round 字段,基于单时间轮原理之下,我们在每个bucket块下不单单存储到期时间expire时间的任务,还会存储一个新字段round(expire%N=bucket的定时器(N为bucket个数))。主要由一下两个字段组成expire:代表到期时间round:表示时间轮要在转动几圈之后才执行任务执行bucket下的延时逻辑
  当指针转到某个bucket时,不能像简单的单时间轮那样直接执行bucket下所有的定时器,而是要去遍历该bucket下的链表,判断判断时间轮转动的次数是否等于节点中的round值,只有当expire和round都相同的情况下,才能执行该任务。
  轮询线程的执行逻辑是每隔一秒处理一个时间刻度上任务队列中的所有任务,任务的 round字段减 1,接着判断如果 round 字段的值变为 0,那么将任务移出任务队列,交给异步线程池来执行对应任务。如果是重复执行任务,那么再将任务添加到任务队列中。
  轮数计算的公式
  轮询线程遍历一次时间轮需要60 秒,如果一个任务需要间隔x秒执行一次,那么其 round 字段的值为 x/60(整除),任务位于第 (x%60)(取余)个刻度对应的任务队列中。
  例如,任务需要间隔 130 秒执行一次,那么 round 字段的值为 2,此任务位于第 10 号时间刻度的任务队列中。
  时间轮round次数:根据计算的需要走的(总次数- 当前tick数量)/ 时间格个数(wheel.length)。提取计算对应的bucket下的任务数据
  比如,tickDuration为1ms,时间格个数为20个,那么时间轮走一圈需要20ms,那么添加进一个延时为24ms的数据,如果当前的tick为0,那么计算出的轮数为1,指针没运行一圈就会将round取出来-1,所以需要转动到第二轮之后才可以将轮数round减为0之后才会运行。轮数时间轮的问题和缺点
  改进版单时间轮是时间和空间折中的方案,不像单时间轮那样有O(1)的时间复杂度,也不会像单时间轮那样,为了满足需求产生大量的bucket。但是这种方式虽然简化了时间轮的刻度个数,但是并没有简化运行效率不高的问题。运行效率不高的问题
  改进版的时间轮如果某个bucket上挂载的定时器特别多,那么需要花费大量的时间去遍历这些节点,如果bucket下的链表每个节点的round都不相同,那么一次遍历下来可能只有极少数的定时器需要立刻执行的,因此很难在时间和空间上都达到理想效果。
  时间轮每次处理一个时间刻度,就需要处理其上任务队列的所有任务。其运行效率甚至与基于普通任务队列实现的定时任务框架没有区别。层级时间轮基本逻辑模型
  为了解决单时轮和轮数时间轮引起的性能问题和资源问题的另一种方式是在层次结构中使用多个定时轮,由多个层级来进行多次hash进行任务数据的传递,从而减少对应的时间和空间的复杂程度。多级时间轮
  【年、月、日、小时、分钟、秒】级别的6个时间轮,每个时间轮分别有(10-年暂时定为10年)、12(月)、24(时)、60(分钟)、60(秒)个刻度。子轮转动一圈,父轮转动一格,从父向子前进,无子过期。分层时间轮如下图所示:
  案例流程执行体系
  任务需要在当天的17:30:20执行任务添加于秒级别时钟轮的第20号Bucket上,当其轮询线程访问到第20号Bucket时,就将此任务转移到分钟级别时钟轮的第30号Bucket上。当分钟级别的时钟轮线程访问到第30号Bucket,就将此任务转移到小时级别时钟轮的第 7号Bucket上。当小时级别时钟轮线程访问到第7号bucket时。
  最终会将任务交给异步线程负责执行,然后将任务再次注册到秒级别的时间轮中。分层时钟轮算法设计具有如下的优点轮询线程效率变高:首先不再需要计算round值,其次任务队列中的任务一旦被遍历,就是需要被处理的(没有空轮询问题)。线程并发性好:虽然引入了并发线程,但是线程数仅仅和时钟轮的级数有关,并不随着任务数的增多而改变。如果任务按照分钟级别来定时执行,那么当分钟时间轮达到对应刻度时,就会将任务交给异步线程来处理,然后将任务再次注册到秒级别的时钟轮上。
  分层时间轮中的任务从一个时间轮转移到另一个时间轮,实现层级轮算法可以借鉴了生活中水表的度量方法,通过低刻度走得快的轮子带动高一级刻度轮子走动的方法,达到了仅使用较少刻度即可表示很大范围度量值的效果。

湖人球员获票详情老詹球迷票数前场第一浓眉球迷票数前场第3直播吧1月27日讯犹他全明星投票结果出炉,詹姆斯入围西部全明星首发阵容,并当选队长。詹姆斯球迷票数位列西部前场第一,球员票数和媒体票数均仅次于约基奇排在第二。其他湖人球员中,浓眉球姚晨一家回老家过年,穿粉色毛衣好减龄,和儿子大街上迎财神姚晨一家四口人回老家福建漳州过年,一家人同框温馨又幸福,和亲戚朋友一起吃席,性格随和打扮得低调。姚晨和家人亲戚朋友吃年夜饭,穿粉色毛衣,时尚又减龄,长发披肩看上去清新靓丽,从容大气专家们,你们为什么总是盯着老百姓的钱袋子?专家们,你们为什么总是盯着老百姓的钱袋子不放?如果老百姓总盯着富人的钱袋子可以吗?近日,有位经济学专家又出来建议了对50万以上存款征收高额利息税,以达到促进消费的目的。建议一出,马世卫突然更新核辐射药物清单!3大原因要考虑,核战争即将爆发?紧急情况!世界卫生组织官网在1月27日突然更新了应对辐射和核紧急情况建议储备的药物清单,这个举动还是自2017年以来的首次。我在网上刚看到这个消息的时候,其实是有点害怕的,因为世卫探索中亚的未知世界中亚行纪作者埃丽卡法特兰豆瓣评分8。9内容梗概社会人类学家埃丽卡法特兰带领读者来到五个斯坦国。这片广袤的前苏联加盟共和国古代丝绸之路的土地上,发生的故事似乎一直被人们忽视。翻开这本书,你将黑米紫米燕麦的营养价值极为突出,每天都应该吃点,不吃很亏2022生机大会对于黑米和紫米,很多人都容易混淆,从两者的区别上来看,确实有一定的差别,大家可根据自身情况进行购买。黑米紫米都是粗粮,且营养价值极高,尤其适合有慢性病基础的人群食用日本房价崩盘回忆当年那些选择不买房的人,后来都怎么样了很多中国人的传统思想当中,只有购买了属于自己的房产,才算是拥有了一个家。而拥有同样思想的还有日本人,日本作为发达国家,房地产行业一度成为了最火爆的投资,甚至还吸引到了不少海外投资者工道专题春节之际,万家团圆之时,有这样一群人,坚守岗位奋战一线,他们是快递小哥外卖员公交司机,是民生保障一线的技术人员他们忙碌着奔跑着,只为守护更多人的团圆。他们用坚守奋斗,刻画出节日里一星际水下猛兽小丑2023春夏高定的灵感迸发2023春夏高级定制时装周刚刚落下帷幕,在短短的四天时间里,近30个品牌带来了象征自家工艺水准与创新精神的全新系列,展现着当下高级定制服在时尚领域不可撼动的地位。在看过各大品牌的新韩国猛虎重创中国搏击!连续秒杀两大高手!去年,UFC开启了一场名为精英之路的选拔赛,该赛事一共开设了蝇量级(57公斤)雏量级(61公斤)羽量级(66公斤)与轻量级(70公斤)四个级别,每个级别共有八位拳手出战,最终的胜者那些年,中国足球错过的天才去年的大年初一,顶替李铁执教男足国家队的李霄鹏耻辱地输给了越南国家队,虽然很多人都预料到会输越南,但没想到输得这么干脆,就在几年前,郜林那批国家队还能六球击败越南,而现在连赢越南也
这一本长在我心巴上的书,实在美!读许渊冲那些优美的古诗翻译ADancerSongsofBeiWithmainandmightDancestheace。Sunatitsheight,Heholdshisplace。HedanceslongW知多D闭环泡泡怎么用?你想知道的都在这里了第29期11月27日晚,海珠区关于调整社会面疫情防控措施的通告发布,其中提到将采取闭环泡泡的防控模式有序推动复工复产。什么是闭环泡泡防控模式?以往有实践过吗?怎么申请实施闭环泡泡?日本通胀爆回40年前,同样实行的宽松货币,对我们有何警示?日本在失去的30年内,一直希望实现通胀达到2的目标,从而摆脱常年通货紧缩的情况,但这次似乎玩大了!近日,日本公布的数据,11月不含生鲜的核心CPI已经上涨了3。6,创下了1982年4。8亿拿下关联方亏损资产,金新农加大布局楼房养猪是否明智?记者庞宇编辑近期,金新农(002548。SZ)发布公告,拟以4。8亿元收购广州金农现代农业有限公司(以下简称金农现代)100股权,目的是进一步发展生猪养殖业务。据悉,本次交易对手中明太祖朱元璋从牛郎成长为君王,这是一部令人钦佩的创业史历史上有很多白手起家的皇帝,比如刘邦昭烈皇帝刘备等等。但明太祖朱元璋是名副其实的乞丐皇帝,从一个放牛娃成长为明朝开国皇帝。他的创业经历令人惊叹。朱元璋原名朱重八,源于他在家族中排行慈禧和光绪唯一被拍到的照片慈禧微笑挥手致意,光绪低头不语说到晚清,有一个人不得不提,就是慈禧太后。这个站在权力之巅的女人,几乎决定了中国历史的走向,连光绪皇帝也被她玩弄于股掌。慈禧是怎么成为中国最有权势的女人的?这张照片给出了答案。照片古代人穿什么样的短裤?纨绔子弟的由来汉代之前古人根本就不穿短裤甚至他们连裤子都不穿还把穿裤子的人视为是蛮夷,不文明的人可以作为对比的就是为了方便骑马而不得不穿裤子的游牧民族中原人称他们为胡人战国时代赵国的君主赵武灵王古代四大丑女嫫母钟无艳孟光阮氏女四大丑女,是指中国历史上的嫫母钟无艳孟光阮氏女四个女人,她们在历代文人笔下也时常出现。中国历史上有西施貂蝉杨贵妃王昭君四大美女。这四大美女常常成为历代文人骚客或褒或贬的吟咏对象。世5岁孩童被凌迟,没想途中昏迷,可慈禧继续下令,救活他,继续割救活后,继续割!1863年,慈禧下令将一个5岁孩童凌迟处死,刽子手才割几刀他就昏迷过去,可慈禧不放人,下令继续行刑。这个五岁孩童是谁?慈禧为何要对一个乳声乳气的小孩下毒手!这一切都这是一组100多年前的老照片,近代的老百姓生活真是太苦了这是民国时期中国人千奇百怪的生活状态,普通老百姓大多生活在水深火热之中。民国时期(年月不详),一名盲人乞丐蜷缩在街边正在向过往的路人乞讨,盲人面前的铁罐看上去几乎没有路人施舍的钱物清朝皇帝打赏的金瓜子究竟是什么?为何妃子们都爱不释手?甄嬛传里,小主沈眉庄曾赏给太监总管苏培盛一捧金瓜子,这些金瓜子让苏培盛喜不自胜,连忙感谢沈眉庄。在影视剧中,我们时常能见到后宫嫔妃打赏太监宫女,但这种金瓜子究竟是什么?让见过世面的