睡眠
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++
}