本文共 2610 字,大约阅读时间需要 8 分钟。
var d = 5*time.Secondtime.Sleep(d)
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) return t}func sendTime(c interface{ }, seq uintptr) { // Non-blocking send of time on c. // Used in NewTimer, it cannot block anyway (buffer). // Used in NewTicker, dropping sends on the floor is // the desired behavior when the reader gets behind, // because the sends are periodic. select { case c.(chan Time) <- Now(): default: }}
timer 的运行机制是,当达到结束时间了,就会调用 f 函数,也就是 sendTime 函数,此函数会向 c 通道中写入当前时间,此函数的实现可以看出它并不保证一定会写入成功,只有当 timer.C 正在被读取时才会写入成功。
所以使用 timer 时你需要读取 timer.C 通道。
tr := time.NewTimer(d)fmt.Println(<-tr.C)
提前终止定时器
func (t *Timer) Stop() bool
重新设置定时器
func (t *Timer) Reset(d Duration) bool
func After(d Duration) <-chan Time { return NewTimer(d).C}
After的使用:
c := time.After(d)ti := <-cfmt.Println(ti)
After实现超时控制
ch1 := make(chan int)go func() { time.Sleep(10 * time.Second) ch1 <- 1}()select { case <-ch1: fmt.Println("get msg")case <-time.After(d): fmt.Println("timeout")}
这是一种同步阻塞的方式来实现的超时控制。
还有一种异步的方式来控制超时。
ch1 := make(chan int)ch2 := make(chan int)time.AfterFunc(d, func() { ch2<-1})go func() { time.Sleep(10 * time.Second) ch1 <- 1}()select { case <-ch1: fmt.Println("get msg")case <-ch2: fmt.Println("timeout")}
来看看 AfterFunc 的实现:
// AfterFunc waits for the duration to elapse and then calls f// in its own goroutine. It returns a Timer that can// be used to cancel the call using its Stop method.func AfterFunc(d Duration, f func()) *Timer { t := &Timer{ r: runtimeTimer{ when: when(d), f: goFunc, arg: f, }, } startTimer(&t.r) return t}func goFunc(arg interface{ }, seq uintptr) { go arg.(func())()}
时间结束后会开启一个 goroutine 来运行 f 函数。
context包中的WithTimeout()就是使用的AfterFunc。
func NewTicker(d Duration) *Ticker { if d <= 0 { panic(errors.New("non-positive interval for NewTicker")) } // Give the channel a 1-element time buffer. // If the client falls behind while reading, we drop ticks // on the floor until the client catches up. c := make(chan Time, 1) t := &Ticker{ C: c, r: runtimeTimer{ when: when(d), period: int64(d), f: sendTime, arg: c, }, } startTimer(&t.r) return t}
也是使用的通道来实现的通知。
for c := range time.NewTicker(d).C { fmt.Println(c)}// 或者for c := range time.Tick(d) { fmt.Println(c)}
带条件终止ticker
tick := time.NewTicker(d)n := 1for c := range tick.C { fmt.Println(c) if n >= 3 { tick.Stop() return } n++}
转载地址:http://tnaui.baihongyu.com/