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:
    }
}

 

posted @ 2020-05-27 22:35  是的哟  阅读(214)  评论(0编辑  收藏  举报