aceld
6 years ago
8 changed files with 706 additions and 0 deletions
-
53ztimer/delayfunc.go
-
23ztimer/delayfunc_test.go
-
85ztimer/timer.go
-
32ztimer/timer_test.go
-
135ztimer/timerscheduler.go
-
67ztimer/timerscheduler_test.go
-
224ztimer/timewheel.go
-
87ztimer/timewheel_test.go
@ -0,0 +1,53 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/4/30 11:57 |
|||
* @Mail: danbing.at@gmail.com |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"fmt" |
|||
"reflect" |
|||
"zinx/zlog" |
|||
) |
|||
|
|||
/* |
|||
定义一个延迟调用函数 |
|||
延迟调用函数就是 时间定时器超时的时候,触发的事先注册好的 |
|||
回调函数 |
|||
*/ |
|||
type DelayFunc struct { |
|||
f func(...interface{}) //f : 延迟函数调用原型
|
|||
args []interface{} //args: 延迟调用函数传递的形参
|
|||
} |
|||
|
|||
/* |
|||
创建一个延迟调用函数 |
|||
*/ |
|||
func NewDelayFunc(f func(v ...interface{}), args []interface{}) *DelayFunc { |
|||
return &DelayFunc{ |
|||
f:f, |
|||
args:args, |
|||
} |
|||
} |
|||
|
|||
//打印当前延迟函数的信息,用于日志记录
|
|||
func (df *DelayFunc) String() string { |
|||
return fmt.Sprintf("{DelayFun:%s, args:%v}", reflect.TypeOf(df.f).Name(), df.args) |
|||
} |
|||
|
|||
|
|||
|
|||
/* |
|||
执行延迟函数---如果执行失败,抛出异常 |
|||
*/ |
|||
func (df *DelayFunc) Call() { |
|||
defer func() { |
|||
if err := recover(); err != nil { |
|||
zlog.Error(df.String(), "Call err: ", err) |
|||
} |
|||
}() |
|||
|
|||
//调用定时器超时函数
|
|||
df.f(df.args...) |
|||
} |
@ -0,0 +1,23 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/4/30 15:17 |
|||
* @Mail: danbing.at@gmail.com |
|||
* |
|||
* 针对 delayFunc.go 做单元测试,主要测试延迟函数结构体是否正常使用 |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"fmt" |
|||
"testing" |
|||
) |
|||
|
|||
func SayHello(message ...interface{}) { |
|||
fmt.Println(message[0].(string), " ",message[1].(string)) |
|||
} |
|||
|
|||
func TestDelayfunc(t *testing.T) { |
|||
df := NewDelayFunc(SayHello, []interface{}{"hello", "zinx!"}) |
|||
fmt.Println("df.String() = ", df.String()) |
|||
df.Call() |
|||
} |
@ -0,0 +1,85 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/4/30 17:42 |
|||
* @Mail: danbing.at@gmail.com |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"time" |
|||
) |
|||
|
|||
const ( |
|||
HOUR_NAME = "HOUR" |
|||
HOUR_INTERVAL = 60*60*1e3 //ms为精度
|
|||
HOUR_SCALES = 12 |
|||
|
|||
MINUTE_NAME = "MINUTE" |
|||
MINUTE_INTERVAL = 60 * 1e3 |
|||
MINUTE_SCALES = 60 |
|||
|
|||
SECOND_NAME = "SECOND" |
|||
SECOND_INTERVAL = 1e3 |
|||
SECOND_SCALES = 60 |
|||
|
|||
TIMERS_MAX_CAP = 2048 //每个时间轮刻度挂载定时器的最大个数
|
|||
) |
|||
|
|||
/* |
|||
注意: |
|||
有关时间的几个换算 |
|||
time.Second(秒) = time.Millisecond * 1e3 |
|||
time.Millisecond(毫秒) = time.Microsecond * 1e3 |
|||
time.Microsecond(微秒) = time.Nanosecond * 1e3 |
|||
|
|||
time.Now().UnixNano() ==> time.Nanosecond (纳秒) |
|||
*/ |
|||
|
|||
/* |
|||
定时器实现 |
|||
*/ |
|||
type Timer struct { |
|||
//延迟调用函数
|
|||
delayFunc *DelayFunc |
|||
//调用时间(unix 时间, 单位ms)
|
|||
unixts int64 |
|||
} |
|||
|
|||
//返回1970-1-1至今经历的毫秒数
|
|||
func UnixMilli() int64 { |
|||
return time.Now().UnixNano() / 1e6 |
|||
} |
|||
|
|||
/* |
|||
创建一个定时器,在指定的时间触发 定时器方法 |
|||
df: DelayFunc类型的延迟调用函数类型 |
|||
unixNano: unix计算机从1970-1-1至今经历的纳秒数 |
|||
*/ |
|||
func NewTimerAt(df *DelayFunc, unixNano int64) *Timer { |
|||
return &Timer{ |
|||
delayFunc: df, |
|||
unixts: unixNano / 1e6, //将纳秒转换成对应的毫秒 ms ,定时器以ms为最小精度
|
|||
} |
|||
} |
|||
|
|||
/* |
|||
创建一个定时器,在当前时间延迟duration之后触发 定时器方法 |
|||
*/ |
|||
func NewTimerAfter(df *DelayFunc, duration time.Duration) *Timer { |
|||
return NewTimerAt(df, time.Now().UnixNano()+int64(duration)) |
|||
} |
|||
|
|||
//启动定时器,用一个go承载
|
|||
func (t *Timer) Run() { |
|||
go func() { |
|||
now := UnixMilli() |
|||
//设置的定时器是否在当前时间之后
|
|||
if t.unixts > now { |
|||
//睡眠,直至时间超时,已微秒为单位进行睡眠
|
|||
time.Sleep(time.Duration(t.unixts-now) * time.Millisecond) |
|||
} |
|||
|
|||
//调用事先注册好的超时延迟方法
|
|||
t.delayFunc.Call() |
|||
}() |
|||
} |
@ -0,0 +1,32 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/5/5 10:14 |
|||
* @Mail: danbing.at@gmail.com |
|||
* |
|||
* 针对timer.go做单元测试,主要测试定时器相关接口 依赖模块delayFunc.go |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"fmt" |
|||
"testing" |
|||
"time" |
|||
) |
|||
|
|||
//定义一个超时函数
|
|||
func myFunc(v ...interface{}) { |
|||
fmt.Printf("No.%d function calld. delay %d second(s)\n", v[0].(int), v[1].(int)) |
|||
} |
|||
|
|||
func TestTimer(t *testing.T) { |
|||
|
|||
|
|||
for i:=0; i < 5;i ++ { |
|||
go func(i int) { |
|||
NewTimerAfter(NewDelayFunc(myFunc,[]interface{}{i, 2*i}), time.Duration(2*i)*time.Second).Run() |
|||
}(i) |
|||
} |
|||
|
|||
//主进程等待其他go,由于Run()方法是用一个新的go承载延迟方法,这里不能用waitGroup
|
|||
time.Sleep(1*time.Minute) |
|||
} |
@ -0,0 +1,135 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/5/8 17:43 |
|||
* @Mail: danbing.at@gmail.com |
|||
* |
|||
* 时间轮调度器 |
|||
* 依赖模块,delayfunc.go timer.go timewheel.go |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"math" |
|||
"sync" |
|||
"time" |
|||
"zinx/zlog" |
|||
) |
|||
|
|||
const ( |
|||
//默认缓冲触发函数队列大小
|
|||
MAX_CHAN_BUFF = 2048 |
|||
//默认最大误差时间
|
|||
MAX_TIME_DELAY = 100 |
|||
) |
|||
|
|||
type TimerScheduler struct { |
|||
//当前调度器的最高级时间轮
|
|||
tw *TimeWheel |
|||
//定时器编号累加器
|
|||
idGen uint32 |
|||
//已经触发定时器的channel
|
|||
triggerChan chan *DelayFunc |
|||
//互斥锁
|
|||
sync.RWMutex |
|||
} |
|||
|
|||
/* |
|||
返回一个定时器调度器 |
|||
|
|||
主要创建分层定时器,并做关联,并依次启动 |
|||
*/ |
|||
func NewTimerScheduler() *TimerScheduler { |
|||
|
|||
//创建秒级时间轮
|
|||
second_tw := NewTimeWheel(SECOND_NAME, SECOND_INTERVAL, SECOND_SCALES, TIMERS_MAX_CAP) |
|||
//创建分钟级时间轮
|
|||
minute_tw := NewTimeWheel(MINUTE_NAME, MINUTE_INTERVAL, MINUTE_SCALES, TIMERS_MAX_CAP) |
|||
//创建小时级时间轮
|
|||
hour_tw := NewTimeWheel(HOUR_NAME, HOUR_INTERVAL, HOUR_SCALES, TIMERS_MAX_CAP) |
|||
|
|||
//将分层时间轮做关联
|
|||
hour_tw.AddTimeWheel(minute_tw) |
|||
minute_tw.AddTimeWheel(second_tw) |
|||
|
|||
//时间轮运行
|
|||
second_tw.Run() |
|||
minute_tw.Run() |
|||
hour_tw.Run() |
|||
|
|||
return &TimerScheduler{ |
|||
tw:hour_tw, |
|||
triggerChan:make(chan *DelayFunc, MAX_CHAN_BUFF), |
|||
} |
|||
} |
|||
|
|||
//创建一个定点Timer 并将Timer添加到分层时间轮中, 返回Timer的tid
|
|||
func (this *TimerScheduler) CreateTimerAt(df *DelayFunc, unixNano int64)(uint32, error) { |
|||
this.Lock() |
|||
defer this.Unlock() |
|||
|
|||
this.idGen++ |
|||
return this.idGen, this.tw.AddTimer(this.idGen, NewTimerAt(df, unixNano)) |
|||
} |
|||
|
|||
//创建一个延迟Timer 并将Timer添加到分层时间轮中, 返回Timer的tid
|
|||
func (this *TimerScheduler) CreateTimerAfter(df *DelayFunc, duration time.Duration)(uint32, error) { |
|||
this.Lock() |
|||
defer this.Unlock() |
|||
|
|||
this.idGen++ |
|||
return this.idGen, this.tw.AddTimer(this.idGen, NewTimerAfter(df, duration)) |
|||
} |
|||
|
|||
//删除timer
|
|||
func(this *TimerScheduler) CancelTimer(tid uint32) { |
|||
this.Lock() |
|||
this.Unlock() |
|||
|
|||
this.tw.RemoveTimer(tid) |
|||
} |
|||
|
|||
//获取计时结束的延迟执行函数通道
|
|||
func (this *TimerScheduler) GetTriggerChan() chan *DelayFunc { |
|||
return this.triggerChan |
|||
} |
|||
|
|||
//非阻塞的方式启动timerSchedule
|
|||
func (this *TimerScheduler) Start() { |
|||
go func() { |
|||
for { |
|||
//当前时间
|
|||
now := UnixMilli() |
|||
//获取最近MAX_TIME_DELAY 毫秒的超时定时器集合
|
|||
timerList := this.tw.GetTimerWithIn(MAX_TIME_DELAY * time.Millisecond) |
|||
for _, timer := range timerList { |
|||
if math.Abs(float64(now-timer.unixts)) > MAX_TIME_DELAY { |
|||
//已经超时的定时器,报警
|
|||
zlog.Error("want call at ", timer.unixts, "; real call at", now, "; delay ", now-timer.unixts) |
|||
} |
|||
//将超时触发函数写入管道
|
|||
this.triggerChan <- timer.delayFunc |
|||
} |
|||
|
|||
|
|||
time.Sleep(MAX_TIME_DELAY/2 * time.Millisecond) |
|||
} |
|||
}() |
|||
} |
|||
|
|||
//时间轮定时器 自动调度
|
|||
func NewAutoExecTimerScheduler() *TimerScheduler{ |
|||
//创建一个调度器
|
|||
autoExecScheduler := NewTimerScheduler() |
|||
//启动调度器
|
|||
autoExecScheduler.Start() |
|||
|
|||
//永久从调度器中获取超时 触发的函数 并执行
|
|||
go func() { |
|||
delayFuncChan := autoExecScheduler.GetTriggerChan() |
|||
for df := range delayFuncChan { |
|||
go df.Call() |
|||
} |
|||
}() |
|||
|
|||
return autoExecScheduler |
|||
} |
@ -0,0 +1,67 @@ |
|||
/** |
|||
* @Author: Aceld(刘丹冰) |
|||
* @Date: 2019/5/9 10:14 |
|||
* @Mail: danbing.at@gmail.com |
|||
* |
|||
* 时间轮定时器调度器单元测试 |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"fmt" |
|||
"testing" |
|||
"time" |
|||
"zinx/zlog" |
|||
) |
|||
|
|||
//触发函数
|
|||
func foo(args ...interface{}){ |
|||
fmt.Printf("I am No. %d function, delay %d ms\n", args[0].(int), args[1].(int)) |
|||
} |
|||
|
|||
//手动创建调度器运转时间轮
|
|||
func TestNewTimerScheduler(t *testing.T) { |
|||
timerScheduler := NewTimerScheduler() |
|||
timerScheduler.Start() |
|||
|
|||
//在scheduler中添加timer
|
|||
for i := 1; i < 2000; i ++ { |
|||
f := NewDelayFunc(foo, []interface{}{i, i*3}) |
|||
tid, err := timerScheduler.CreateTimerAfter(f, time.Duration(3*i) * time.Millisecond) |
|||
if err != nil { |
|||
zlog.Error("create timer error", tid, err) |
|||
break |
|||
} |
|||
} |
|||
|
|||
//执行调度器触发函数
|
|||
go func() { |
|||
delayFuncChan := timerScheduler.GetTriggerChan() |
|||
for df := range delayFuncChan { |
|||
df.Call() |
|||
} |
|||
}() |
|||
|
|||
//阻塞等待
|
|||
select{} |
|||
} |
|||
|
|||
//采用自动调度器运转时间轮
|
|||
func TestNewAutoExecTimerScheduler(t *testing.T) { |
|||
autoTS := NewAutoExecTimerScheduler() |
|||
|
|||
//给调度器添加Timer
|
|||
for i := 0; i < 2000; i ++ { |
|||
f := NewDelayFunc(foo, []interface{}{i, i*3}) |
|||
tid, err := autoTS.CreateTimerAfter(f, time.Duration(3*i) * time.Millisecond) |
|||
if err != nil { |
|||
zlog.Error("create timer error", tid, err) |
|||
break |
|||
} |
|||
} |
|||
|
|||
//阻塞等待
|
|||
select{} |
|||
} |
|||
|
|||
|
@ -0,0 +1,224 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/4/30 11:57 |
|||
* @Mail: danbing.at@gmail.com |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"sync" |
|||
"time" |
|||
"zinx/zlog" |
|||
) |
|||
|
|||
/* |
|||
tips: |
|||
一个网络服务程序时需要管理大量客户端连接的, |
|||
其中每个客户端连接都需要管理它的 timeout 时间。 |
|||
通常连接的超时管理一般设置为30~60秒不等,并不需要太精确的时间控制。 |
|||
另外由于服务端管理着多达数万到数十万不等的连接数, |
|||
因此我们没法为每个连接使用一个Timer,那样太消耗资源不现实。 |
|||
|
|||
用时间轮的方式来管理和维护大量的timer调度,会解决上面的问题。 |
|||
*/ |
|||
|
|||
type TimeWheel struct { |
|||
//TimeWheel的名称
|
|||
name string |
|||
//刻度的时间间隔,单位ms
|
|||
interval int64 |
|||
//每个时间轮上的刻度数
|
|||
scales int |
|||
//当前时间指针的指向
|
|||
curIndex int |
|||
//每个刻度所存放的timer定时器的最大容量
|
|||
maxCap int |
|||
//当前时间轮上的所有timer
|
|||
timerQueue map[int]map[uint32]*Timer //map[int] VALUE 其中int表示当前时间轮的刻度,
|
|||
// map[int] map[uint32] *Timer, uint32表示Timer的id号
|
|||
//下一层时间轮
|
|||
nextTimeWheel *TimeWheel |
|||
//互斥锁(继承RWMutex的 RWLock,UnLock 等方法)
|
|||
sync.RWMutex |
|||
} |
|||
|
|||
/* |
|||
创建一个时间轮 |
|||
name:时间轮的名称 |
|||
interval:每个刻度之间的duration时间间隔 |
|||
scales:当前时间轮的轮盘一共多少个刻度(如我们正常的时钟就是12个刻度) |
|||
maxCap: 每个刻度所最大保存的Timer定时器个数 |
|||
*/ |
|||
func NewTimeWheel(name string, interval int64, scales int, maxCap int) *TimeWheel { |
|||
tw := &TimeWheel{ |
|||
name: name, |
|||
interval: interval, |
|||
scales: scales, |
|||
maxCap: maxCap, |
|||
timerQueue: make(map[int]map[uint32]*Timer, scales), |
|||
} |
|||
//初始化map
|
|||
for i := 0; i < scales; i++ { |
|||
tw.timerQueue[i] = make(map[uint32]*Timer, maxCap) |
|||
} |
|||
|
|||
zlog.Info("Init timerWhell name = ", tw.name, " is Done!") |
|||
return tw |
|||
} |
|||
|
|||
/* |
|||
将一个timer定时器加入到分层时间轮中 |
|||
tid: 每个定时器timer的唯一标识 |
|||
t: 当前被加入时间轮的定时器 |
|||
forceNext: 是否强制的将定时器添加到下一层时间轮 |
|||
|
|||
我们采用的算法是: |
|||
如果当前timer的超时时间间隔 大于一个刻度,那么进行hash计算 找到对应的刻度上添加 |
|||
如果当前的timer的超时时间间隔 小于一个刻度 : |
|||
如果没有下一轮时间轮 |
|||
*/ |
|||
func (tw *TimeWheel) addTimer(tid uint32, t *Timer, forceNext bool) error { |
|||
defer func() error { |
|||
if err := recover(); err != nil { |
|||
errstr := fmt.Sprintf("addTimer function err : %s", err) |
|||
zlog.Error(errstr) |
|||
return errors.New(errstr) |
|||
} |
|||
return nil |
|||
}() |
|||
|
|||
//得到当前的超时时间间隔(ms)毫秒为单位
|
|||
delayInterval := t.unixts - UnixMilli() |
|||
|
|||
//如果当前的超时时间 大于一个刻度的时间间隔
|
|||
if delayInterval >= tw.interval { |
|||
//得到需要跨越几个刻度
|
|||
dn := delayInterval / tw.interval |
|||
//在对应的刻度上的定时器Timer集合map加入当前定时器(由于是环形,所以要求余)
|
|||
tw.timerQueue[(tw.curIndex+int(dn))%tw.scales][tid] = t |
|||
|
|||
return nil |
|||
} |
|||
|
|||
//如果当前的超时时间,小于一个刻度的时间间隔,并且当前时间轮没有下一层,经度最小的时间轮
|
|||
if delayInterval < tw.interval && tw.nextTimeWheel == nil { |
|||
if forceNext == true { |
|||
//如果设置为强制移至下一个刻度,那么将定时器移至下一个刻度
|
|||
//这种情况,主要是时间轮自动轮转的情况
|
|||
//因为这是底层时间轮,该定时器在转动的时候,如果没有被调度者取走的话,该定时器将不会再被发现
|
|||
//因为时间轮刻度已经过去,如果不强制把该定时器Timer移至下时刻,就永远不会被取走并触发调用
|
|||
//所以这里强制将timer移至下个刻度的集合中,等待调用者在下次轮转之前取走该定时器
|
|||
tw.timerQueue[(tw.curIndex+1) % tw.scales][tid] = t |
|||
} else { |
|||
//如果手动添加定时器,那么直接将timer添加到对应底层时间轮的当前刻度集合中
|
|||
tw.timerQueue[tw.curIndex][tid] = t |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
//如果当前的超时时间,小于一个刻度的时间间隔,并且有下一层时间轮
|
|||
if delayInterval < tw.interval { |
|||
return tw.nextTimeWheel.AddTimer(tid, t) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
//添加一个timer到一个时间轮中(非时间轮自转情况)
|
|||
func (tw *TimeWheel) AddTimer(tid uint32, t *Timer) error { |
|||
tw.Lock() |
|||
defer tw.Unlock() |
|||
|
|||
return tw.addTimer(tid, t, false) |
|||
} |
|||
|
|||
/* |
|||
删除一个定时器,根据定时器的id |
|||
*/ |
|||
func (tw *TimeWheel) RemoveTimer(tid uint32) { |
|||
tw.Lock() |
|||
defer tw.Unlock() |
|||
|
|||
for i := 0; i < tw.scales; i++ { |
|||
if _, ok := tw.timerQueue[i][tid]; ok { |
|||
delete(tw.timerQueue[i], tid) |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* |
|||
给一个时间轮添加下层时间轮 比如给小时时间轮添加分钟时间轮,给分钟时间轮添加秒时间轮 |
|||
*/ |
|||
func (tw *TimeWheel) AddTimeWheel(next *TimeWheel) { |
|||
tw.nextTimeWheel = next |
|||
zlog.Info("Add timerWhell[", tw.name,"]'s next [", next.name,"] is succ!") |
|||
} |
|||
|
|||
/* |
|||
启动时间轮 |
|||
*/ |
|||
func (tw *TimeWheel) run() { |
|||
for { |
|||
//时间轮每间隔interval一刻度时间,触发转动一次
|
|||
time.Sleep(time.Duration(tw.interval) * time.Millisecond) |
|||
|
|||
tw.Lock() |
|||
//取出挂载在当前刻度的全部定时器
|
|||
curTimers := tw.timerQueue[tw.curIndex] |
|||
//当前定时器要重新添加 所给当前刻度再重新开辟一个map Timer容器
|
|||
tw.timerQueue[tw.curIndex] = make(map[uint32]*Timer, tw.maxCap) |
|||
for tid, timer := range curTimers { |
|||
//这里属于时间轮自动转动,forceNext设置为true
|
|||
tw.addTimer(tid, timer, true) |
|||
} |
|||
|
|||
//取出下一个刻度 挂载的全部定时器 进行重新添加 (为了安全起见,待考慮)
|
|||
nextTimers := tw.timerQueue[(tw.curIndex+1) % tw.scales] |
|||
tw.timerQueue[(tw.curIndex+1) % tw.scales] = make(map[uint32]*Timer, tw.maxCap) |
|||
for tid, timer := range nextTimers { |
|||
tw.addTimer(tid, timer, true) |
|||
} |
|||
|
|||
//当前刻度指针 走一格
|
|||
tw.curIndex = (tw.curIndex+1) % tw.scales |
|||
|
|||
tw.Unlock() |
|||
} |
|||
} |
|||
|
|||
//非阻塞的方式让时间轮转起来
|
|||
func (tw *TimeWheel) Run() { |
|||
go tw.run() |
|||
zlog.Info("timerwheel name = ", tw.name, " is running...") |
|||
} |
|||
|
|||
//获取定时器在一段时间间隔内的Timer
|
|||
func (tw *TimeWheel) GetTimerWithIn(duration time.Duration) map[uint32]*Timer { |
|||
//最终触发定时器的一定是挂载最底层时间轮上的定时器
|
|||
//1 找到最底层时间轮
|
|||
leaftw := tw |
|||
for leaftw.nextTimeWheel != nil { |
|||
leaftw = leaftw.nextTimeWheel |
|||
} |
|||
|
|||
leaftw.Lock() |
|||
defer leaftw.Unlock() |
|||
//返回的Timer集合
|
|||
timerList := make(map[uint32]*Timer) |
|||
|
|||
now := UnixMilli() |
|||
|
|||
//取出当前时间轮刻度内全部Timer
|
|||
for tid, timer := range leaftw.timerQueue[leaftw.curIndex] { |
|||
if timer.unixts-now < int64(duration/1e6) { |
|||
//当前定时器已经超时
|
|||
timerList[tid] = timer |
|||
//定时器已经超时被取走,从当前时间轮上 摘除该定时器
|
|||
delete(leaftw.timerQueue[leaftw.curIndex], tid) |
|||
} |
|||
} |
|||
|
|||
return timerList |
|||
} |
@ -0,0 +1,87 @@ |
|||
/** |
|||
* @Author: Aceld |
|||
* @Date: 2019/5/7 18:00 |
|||
* @Mail: danbing.at@gmail.com |
|||
* |
|||
* 针对 timer_wheel.go 时间轮api 做单元测试, 主要测试时间轮运转功能 |
|||
* 依赖模块 delayFunc.go timer.go |
|||
*/ |
|||
package ztimer |
|||
|
|||
import ( |
|||
"fmt" |
|||
"testing" |
|||
"time" |
|||
) |
|||
|
|||
func TestTimerWheel(t *testing.T) { |
|||
//创建秒级时间轮
|
|||
second_tw := NewTimeWheel(SECOND_NAME, SECOND_INTERVAL, SECOND_SCALES, TIMERS_MAX_CAP) |
|||
|
|||
//创建分钟级时间轮
|
|||
minute_tw := NewTimeWheel(MINUTE_NAME, MINUTE_INTERVAL, MINUTE_SCALES, TIMERS_MAX_CAP) |
|||
|
|||
//创建小时级时间轮
|
|||
hour_tw := NewTimeWheel(HOUR_NAME, HOUR_INTERVAL, HOUR_SCALES, TIMERS_MAX_CAP) |
|||
|
|||
//将分层时间轮做关联
|
|||
hour_tw.AddTimeWheel(minute_tw) |
|||
minute_tw.AddTimeWheel(second_tw) |
|||
|
|||
fmt.Println("init timewheels done!") |
|||
|
|||
|
|||
//===== > 以上为初始化分层时间轮 <====
|
|||
|
|||
//给时间轮添加定时器
|
|||
timer1 := NewTimerAfter(NewDelayFunc(myFunc, []interface{}{1,10}), 10 * time.Second) |
|||
_ = hour_tw.AddTimer(1, timer1) |
|||
fmt.Println("add timer 1 done!") |
|||
|
|||
//给时间轮添加定时器
|
|||
timer2 := NewTimerAfter(NewDelayFunc(myFunc, []interface{}{2,20}), 20 * time.Second) |
|||
_ = hour_tw.AddTimer(2, timer2) |
|||
fmt.Println("add timer 2 done!") |
|||
|
|||
//给时间轮添加定时器
|
|||
timer3 := NewTimerAfter(NewDelayFunc(myFunc, []interface{}{3,30}), 30 * time.Second) |
|||
_ = hour_tw.AddTimer(3, timer3) |
|||
fmt.Println("add timer 3 done!") |
|||
|
|||
//给时间轮添加定时器
|
|||
timer4 := NewTimerAfter(NewDelayFunc(myFunc, []interface{}{4,40}), 40 * time.Second) |
|||
_ = hour_tw.AddTimer(4, timer4) |
|||
fmt.Println("add timer 4 done!") |
|||
|
|||
//给时间轮添加定时器
|
|||
timer5 := NewTimerAfter(NewDelayFunc(myFunc, []interface{}{5,50}), 50 * time.Second) |
|||
_ = hour_tw.AddTimer(5, timer5) |
|||
fmt.Println("add timer 5 done!") |
|||
|
|||
//时间轮运行
|
|||
second_tw.Run() |
|||
minute_tw.Run() |
|||
hour_tw.Run() |
|||
|
|||
fmt.Println("timewheels are run!") |
|||
|
|||
go func() { |
|||
n := 0.0 |
|||
for { |
|||
fmt.Println("tick...", n) |
|||
|
|||
//取出近1ms的超时定时器有哪些
|
|||
timers := hour_tw.GetTimerWithIn(1000 *time.Millisecond) |
|||
for _, timer := range timers { |
|||
//调用定时器方法
|
|||
timer.delayFunc.Call() |
|||
} |
|||
|
|||
time.Sleep(500 * time.Millisecond) |
|||
n += 0.5 |
|||
} |
|||
}() |
|||
|
|||
//主进程等待其他go,由于Run()方法是用一个新的go承载延迟方法,这里不能用waitGroup
|
|||
time.Sleep(10*time.Minute) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue