一个系统中存在着大量的调度任务,同时调度任务存在时间的滞后性,而大量的调度任务如果每一个都使用自己的调度器来管理任务的生命周期的话,浪费cpu的资源而且很低效。
本文来介绍<代码>从0 代码>中延迟操作,它可能让开发者调度多个任务时,只需关注具体的业务执行函数和执行时间“立即或者延迟”。而延迟操作,通常可以采用两个方案:
<代码>时间> 代码:定时器维护一个优先队列,到时间点执行,然后把需要执行的任务存储在地图中<代码> 代码>中集合的<代码> timingWheel> 代码,维护一个存放任务组的数组,每一个槽都维护一个存储任务的双向链表。开始执行时,计时器每隔指定时间执行一个槽里面的任务。
方案2把维护任务从<代码>优先队阿列(nlog (n)) 代码>降到<代码>双向链表O(1)> 代码,而执行任务也只要轮询一个时间点的任务<代码> O (n)> 代码,不需要像优先队列,放入和删除元素<代码> O (nlog (n))> 代码。
我们先看看<代码>从0 代码>中自己对<代码> timingWheel> 代码的使用:
首先我们先来在收集<代码> 代码>的<代码> 代码>中缓存关于<代码> timingWheel> 代码的使用:
timingWheel犯错:=NewTimingWheel(时间。第二,插槽,func (k、v接口{}){ 关键,好的:=k。(字符串) 如果!好{ 返回 } cache.Del(关键) }) 如果犯错!=nil { 返回nil,犯错 } 缓存。timingWheel=timingWheel
这是缓存<代码> 代码>初始化中也同时初始化<代码> timingWheel> 代码做关键的过期处理,参数依次代表:
-
<李> 代码>:<代码>间隔时间划分刻度李>
<李> <代码> numSlots> 代码:时间槽李>
<李> <代码> 代码>:执行时间点执行函数李>
在<代码> >代码缓存中执行函数则是删除过期的关键,而这个过期则由<代码> timingWheel> 代码来控制推进时间。
接下来,就通过缓存<代码> 代码>对<代码> timingWheel> 代码的使用来认识。
//真正做初始化 func newTimingWheelWithClock(间隔时间。持续时间、numSlots int、执行执行股票timex.Ticker) ( * TimingWheel,错误){ tw:=, TimingWheel { 间隔:间隔,//单个时间格时间间隔 股票:股票,//定时器,做时间推动,以间隔为单位推进 槽:使([]*列表。列表、numSlots)//时间轮 计时器:NewSafeMap()//存储任务{键,值}的地图(执行执行所需要的参数) tickedPos: numSlots - 1,//之前的虚拟圆 执行:执行//执行函数 numSlots: numSlots,//初始化槽num setChannel:使(chan timingEntry)//以下几个频道是做任务传递的 moveChannel:使(chan baseEntry), removeChannel:使({})陈接口, drainChannel:使(陈func({})键,值接口), stopChannel:使(chan lang.PlaceholderType), }//把槽中存储的名单全部准备好 tw.initSlots ()//开启异步协程,使用通道来做任务通信和传递 去tw.run () 返回tw,零 } >之前
以上比较直观展示<代码> timingWheel> 代码的“时间轮”,后面会围绕这张图解释其中推进的细节。
<代码>去tw.run() 代码>开一个协程做时间推动:
func (tw * TimingWheel) run () { 为{ 选择{//定时器做时间推动→scanAndRunTasks () & lt; -tw.ticker.Chan (): tw.onTick ()//添加任务会往setChannel输入的任务 任务:=& lt; -tw.setChannel: tw.setTask(任务), … } } }可以看的出,在初始化的时候就开始了<代码>时间> 代码执行,并以<代码> 代码>内部时间段转动,然后底层不停的获取来自<代码>槽> 代码中的<代码> 代码>的任务列表,交给<代码> 代码>执行执行。
紧接着就是设置缓存键<代码> 代码>:
func (c *缓存)组(键字符串值接口{}){ c.lock.Lock () _好:=c.data(例子) c。数据(关键)=价值 c.lruCache.add(关键) c.lock.Unlock () 到期:=c.unstableExpiry.AroundDuration (c.expire) 如果好{ c.timingWheel。MoveTimer(关键,到期) 其他}{ c.timingWheel。凝固时间(关键值,到期) } }做到零如何应对海量定时/延迟任务