1. 程式人生 > 其它 >轉-- Golang中timer定時器實現原理

轉-- Golang中timer定時器實現原理

一般我們匯入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

  1. 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()

     }

   }