用 go 撸了一个时间轮
最近在网上想找个go的时间轮,用于项目当中。在github上浏览下,没找到特别适合的项目,遂自己撸了一个,顺便学习了。有不足之处,还望大家指教
项目地址:~github.com/welllog/timewheel
简单介绍一下:
先贴一个时间轮数据结构
type TimeWheel struct {
randomID uint64
interval time.Duration
ticker *time.Ticker
slotNum int
slots []*list.List
currentPos int
onceStart sync.Once
addTaskC chan *task
stopC chan struct{}
taskRecord sync.Map
}
randomID 自增用来作为添加任务的id,而任务id主要用来移除该任务
interval 为时间轮槽的精度,间隔该时间,指向到下一个槽
ticker 为go 的定时器用来驱动时间轮
slotNum 定义时间轮的槽数
slots 时间轮用数组表示,同一槽的任务用链表来存储
currentPos 时间轮当前指向的位置
addTaskC 添加任务将任务发送到该管道中,异步添加,同时防止并发
stopC 时间轮的停止信号通道
taskRecord 用来存储任务,可以通过该map最快o(1)时间复杂度找到任务
type task struct {
id TaskId
delay time.Duration
circle int
callback func()
mut sync.Mutex
times int32 //-1:no limit >=1:run times
async bool
pool bool
stop bool
run bool
}
任务数据结构
移除任务主要将stop标记为true,在轮询到该任务时才会主动删除任务
run 用来表示该任务是否被运行过,在实现timer.Stop方法时很有用
大概用法:
tw := NewTimeWheel(100 * time.Millisecond, 50)
tw.Start()
defer tw.Stop()
tw.AddOnce(time.Second, func() {
fmt.Println("once")})
var i int
tw.AddWithTimes(time.Second, 5, func() {
i++ fmt.Println(i)})
taskId := tw.AddCron(time.Second, func() {
i++})
tw.RemoveAndHasRun(taskId)
timer := tw.NewTimer(time.Second)
<-timer.C
timer.Reset(500 * time.Millisecond)
timer.Stop()
ticker := tw.NewTicker(500 * time.Millisecond)
var incr int
for {
<-ticker.C incr++
if incr == 20 { ticker.Stop() break }}
<-tw.After(time.Second)
tw.AfterFunc(500 * time.Millisecond, func() {
tw.Sleep(time.Second)
推荐文章: