睡眠
var d = 5*time.Second
time.Sleep(d)
定时器 timer
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 通道中写入当前时间,c 通道是一个长度为 1 的缓存通道,因此写入通道并不会阻塞。
读取 timer.C 通道。
tr := time.NewTimer(d)
fmt.Println(<-tr.C)
提前终止定时器
func (t *Timer) Stop() bool
重新设置定时器
func (t *Timer) Reset(d Duration) bool
timer 的应用:超时控制
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
After的使用:
c := time.After(d)
ti := <-c
fmt.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。
循环定时器 ticker
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 := 1
for c := range tick.C {
fmt.Println(c)if n >= 3 {
tick.Stop()return}n++
}