golang底层 timer ticker
在执行调度循环 runtime.schedule 时,或者系统监控sysmon时,会检查是否有timer就绪。 每次把堆顶timer的when和当前时间作比较,when<nowtime则执行timer里的f,并删除当前timer,如果是ticker,则计算下一次触发的时间,加入到堆中 timer存放在P中: type p struct { timersLock mutex // timers 字段的锁,scheduler 会在不同的 P 上访问timers timers []*timer // 4叉小顶堆 adjustTimers uint32 // 在 P 堆中 timerModifiedEarlier timers 的数量 (...) } p被销毁时,要将timer转移走,p里没有timer时,会从其他p里偷一半的timer -------------------------------------------------------------------------------- timer 和 ticker 数据结构 type Ticker struct { C <-chan Time r runtimeTimer } type Timer struct { C <-chan Time r runtimeTimer } type runtimeTimer struct { pp uintptr // timer 所在的 P 的指针 when int64 period int64 f func(interface{}, uintptr) arg interface{} seq uintptr nextwhen int64 status uint32 } 创建timer func After(d Duration) <-chan Time { return NewTimer(d).C } func NewTimer(d Duration) *Timer { c := make(chan Time, 1) t := &Timer{ C: c, r: runtimeTimer{ when: when(d), f: sendTime, // 发送当前时间 arg: c, }, } startTimer(&t.r) // 调用 addtimer(),插入到堆中 return t } 创建ticker func Tick(d Duration) <-chan Time { if d <= 0 { return nil } return NewTicker(d).C } func NewTicker(d Duration) *Ticker { if d <= 0 { panic(errors.New("non-positive interval for NewTicker")) } c := make(chan Time, 1) t := &Ticker{ C: c, r: runtimeTimer{ when: when(d), period: int64(d), // 多了period,其他和timer一样 f: sendTime, arg: c, }, } startTimer(&t.r) // 调用 addtimer(),插入到堆中 return t } stop func (t *Ticker) Stop() { // Stop后才会释放相关的资源 stopTimer(&t.r) // 调用 deltimer(),从堆中删除 } func (t *Timer) Stop() bool { if t.r.f == nil { panic("time: Stop called on uninitialized Timer") } return stopTimer(&t.r) // 调用 deltimer(),从堆中删除 } reset func (t *Timer) Reset(d Duration) bool { w := when(d) active := stopTimer(&t.r) // 调用 deltimer(),从堆中删除 resetTimer(&t.r, w) // 调整时间 return active } func sendTime(c interface{}, seq uintptr) { select { case c.(chan Time) <- Now(): default: } }