轉-- Golang中timer定時器實現原理
阿新 • • 發佈:2022-05-05
一般我們匯入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()
}
}