用时间轮来实现定时器时,需要定义每一个格子的“刻度”,可以将时间想象成一个时钟,中心有秒针顺时针转动,每次转动到一个刻度时,需要去查看该刻度挂载的任务列表是否已经有到期的任务。
从结构上来讲,时间轮和哈希表很相似,如果把哈希算法定义为:触发时间 % 时间轮元素大小,那么这就是一个简单的哈希表。在哈希冲突时,采用链表挂载哈希冲突的定时器。
除了这种单层时间轮,还有一些时间轮采用多层实现。
用 Go 实现的时间轮项目不多,下面这个是其中性能较好的时间轮的延时任务示例:
package main
import (
"github.com/antlabs/timer"
)
// 一次性定时器
func after(tm timer.Timer) {
var wg sync.WaitGroup
wg.Add(2)
defer wg.Wait()
go func() {
defer wg.Done()
tm.AfterFunc(1*time.Second, func() {
log.Printf("after 1 second\n")
})
}()
go func() {
defer wg.Done()
tm.AfterFunc(10*time.Second, func() {
log.Printf("after 10 seconds\n")
})
}()
go func() {
defer wg.Done()
tm.AfterFunc(30*time.Second, func() {
log.Printf("after 30 seconds\n")
})
}()
go func() {
defer wg.Done()
tm.AfterFunc(time.Minute, func() {
log.Printf("after 1 minute\n")
})
}()
go func() {
defer wg.Done()
tm.AfterFunc(time.Minute+30*time.Second, func() {
log.Printf("after 1 minute and 30 seconds\n")
})
}()
go func() {
defer wg.Done()
tm.AfterFunc(2*time.Minute+45*time.Second, func() {
log.Printf("after 2 minutes and 45 seconds\n")
})
}()
}
// 周期性定时器
func schedule(tm timer.Timer) {
tm.ScheduleFunc(500*time.Millisecond, func() {
log.Printf("schedule 500 milliseconds\n")
})
tm.ScheduleFunc(time.Second, func() {
log.Printf("schedule 1 second\n")
})
tm.ScheduleFunc(20*time.Second, func() {
log.Printf("schedule 20 seconds\n")
})
tm.ScheduleFunc(1*time.Minute, func() {
log.Printf("schedule 1 minute\n")
})
}
func main() {
tm := timer.NewTimer()
defer tm.Stop()
// go after(tm)
go schedule(tm)
go func() {
time.Sleep(2*time.Minute + 50*time.Second)
tm.Stop()
}()
tm.Run()
}
最后编辑: kuteng 文档更新时间: 2022-03-22 19:29 作者:kuteng