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