GO语言实现时间轮| 青训营笔记

487 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天

这是我参与「第五届青训营 」伴学笔记创作活动不水的第 2 天(可能是假的)

我在github上找到了go实现的时间轮算法,把他fork来研究研究.本来代码全糊在一个代码里,这样子是不适合我这种小白阅读的,所以我把代码按功能拆解了一下: github.com/Greenery-S/… 各位看官可以看看,拆的很清晰了,肯定不亏.

这里的时间轮是课中讲解的带count的时间轮,是一种单轮的设计.假如你的时间轮有3600个时间槽,每个时间槽间隔1s,那么它转一轮也就是3600s=1小时.

image.png

那如果有一个定时任务是2小时1秒执行呢? 那么这个任务会被挂载到第一个时间槽且cirle记为2.这意味着:

  • (1s):当时间轮第一次走到一秒的时候,这个任务不会被执行,circle-1=1;
  • (1小时1s):当时间轮转了一圈,再一次走到一秒的时候,这个任务也不会被执行,circle-1=0;
  • (2小时1s):当时间轮转了一圈,再一次走到一秒的时候,circle==0,任务也被执行了.

源码拆解后结构如下:

  • entity.go //定义实体类型
  • init.go //New时间轮对象
  • api.go //初始化时间轮,关闭时间轮api
  • tick.go //时间轮转,执行任务
  • task.go //添加新任务
  • remove.go //删除任务

任务管理中心是一个select-case:

func (tw *TimeWheel) start() {
	for {
		select {
		case <-tw.ticker.C://时间轮转,执行任务
			tw.tickHandler()
		case task := <-tw.addTaskChannel://添加新任务
			tw.addTask(&task)
		case key := <-tw.removeTaskChannel:
			tw.removeTask(key)
		case <-tw.stopChannel://删除任务
			tw.ticker.Stop()
			return
		}
	}
}

go语言的gorutine和channel真的大爱,非常的精妙,非常的优雅,漂亮滴很那! 未来我会深入学学<concurrency in go>这本书.

我尝试在这个基础上做一个分层时间轮,但总是报错"死锁",我很不解,暂时先这样吧.未来有时间我会试着重构一个分层轮的(不负责任挖坑..).