关于什么是时间轮算法,自己百度吧,这里列出我用go语言实现的时间轮算法,已经上线应用,稳定。
package timer
import (
"log"
"sync"
"time"
)
const wheel_cnt uint8 = 5 //时间轮数量5个
var element_cnt_per_wheel = [wheel_cnt]uint32{256, 64, 64, 64, 64} //每个时间轮的槽(元素)数量。在 256+64+64+64+64 = 512 个槽中,表示的范围为 2^32
var right_shift_per_wheel = [wheel_cnt]uint32{8, 6, 6, 6, 6} //当指针指向当前时间轮最后一位数,再走一位就需要向上进位。每个时间轮进位的时候,使用右移的方式,最快实现进位。这里是每个轮的进位二进制位数
var base_per_wheel = [wheel_cnt]uint32{1, 256, 256 * 64, 256 * 64 * 64, 256 * 64 * 64 * 64} //记录每个时间轮指针当前指向的位置
var mutex sync.Mutex //加锁
var rwmutex sync.RWMutex
var newest [wheel_cnt]uint32 //每个时间轮当前指针所指向的位置
var timewheels [5][]*Node //定义5个时间轮
var TimerMap map[string]*Node = make(map[string]*Node) //保存待执行的计时器,方便按链表节点指针地址直接删除定时器
type Timer struct {
Name string //定时器名称
Inteval uint32 //时间间隔,即以插入该定时器的时间为起点,Inteval秒之后执行回调函数DoSomething()。例如进程插入该定时器的时间是2015-04-05 10:23:00,Inteval=5,则执行DoSomething()的时间就是2015-04-05 10:23:05。
DoSomething func(interface{}) //自定义事件处理函数,需要触发的事件
Args interface{} //上述函数的输入参数
}
func SetTimer(name string, inteval uint32, handler func(interface{}), args interface{}) {
if inteval = element_cnt_per_wheel[bucket_no] { //偏移量大于当前时间轮容量,则需要向高位进位
offset >>= right_shift_per_wheel[bucket_no] //计算高位的值。偏移量除以低位的进制。比如低位当前是256,则右移8个二进制位,就是除以256,得到的结果是高位的值。
var tmp uint32 = 1
if bucket_no == 0 {
tmp = 0
}
left -= base_per_wheel[bucket_no] * (element_cnt_per_wheel[bucket_no] - newest[bucket_no] - tmp)
bucket_no++
}
if offset |