一般我们导入import ("time")包,然后调用time.NewTicker(1 * time.Second) 实现一个定时器:
func timer1() {
timer1 := time.NewTicker(1 * time.Second)
for {
select {
case <-timer1.C:
xxx() //执行我们想要的操作
}
}
}
再看看timer包中NewTicker的具体实现:
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
}
其中Ticker的具体struct如下:
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
r runtimeTimer
}
Ticker中的C为数据类型为Time的单向管道,只能读,不能写
再分下一下runtimeTimer的参数:
r: runtimeTimer{
when: when(d),
period: int64(d),
f: sendTime,
arg: c,
}
其中sendTime为回调函数,startTimer时候注册的,arg为回调函数需要的参数arg
startTimer(&t.r)
再进一步看看startTimer的实现:
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:
}
}
通过往管道里面写时间,注意我们Ticker结构里面的C是单向管道,只能读不能写,那要怎么写数据了
通过类型转化,因为channel是一个原生类型,因此不仅支持被传递,还支持类型转换,装换成双向的管道channel,往里面写数据,用户API那边提供的是单向管道,用户只能就只能读数据,就相当于一层限制
最后,调用执行具体xxx函数,实现定时执行某些事件的功能:
for {
select {
case <-timer1.C:
xxxx()
}
}