func timerproc(tb *timersBucket) {
for{
lock(&tb.lock) //加锁
now := nanotime() //当前时间的纳秒值
delta := int64(-1) //最近要执行的timer和当前时间的差值
for{
iflen(tb.t) == 0{
delta = -1
break
}//当前无可执行timer,直接跳出该循环
t := tb.t[0]
delta = t.when - now //取when组小的的timer,计算于当前时间的差值
ifdelta > 0{
break
}// delta大于0,说明还未到发送channel时间,需要跳出循环去睡眠delta时间
ift.period > 0{
// leave in heap but adjust next time to fire
t.when += t.period * (1+ -delta/t.period)// 计算该timer下次执行任务的时间
siftdownTimer(tb.t, 0) //调整堆
} else{
// remove from heap,如果没有设定下次执行时间,则将该timer从堆中移除(time.after和time.sleep函数即是只执行一次定时任务)
last := len(tb.t) - 1
iflast > 0{
tb.t[0] = tb.t[last]
tb.t[0].i = 0
}
tb.t[last] = nil
tb.t = tb.t[:last]
iflast > 0{
siftdownTimer(tb.t, 0)
}
t.i = -1// mark as removed
}
f := t.f
arg := t.arg
seq := t.seq
unlock(&tb.lock)//解锁
f(arg, seq) //在channel中发送time结构体,唤醒阻塞的协程
lock(&tb.lock)
}
ifdelta < 0{
// No timers left - put goroutine to sleep.
goparkunlock(&tb.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
continue
}// delta小于0说明当前无定时任务,直接进行阻塞进行睡眠
tb.sleeping = true
tb.sleepUntil = now + delta
unlock(&tb.lock)
notetsleepg(&tb.waitnote, delta) //睡眠delta时间,唤醒之后就可以执行在堆顶的定时任务了
}
}