go中timer定時器實現原理

通常咱們導入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()
     }
   }
相關文章
相關標籤/搜索