<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## Timer實現原理 每個Go應用程序都有一個協程專門負責管理所有的Timer,這個協程負責監控Timer是否過期,過期后執行一個預定義的動作,這個動作對于Timer而言就是發送當前時間到管道中 源碼包`src/time/sleep.go:Timer`定義了其數據結構: ~~~go type Timer struct { C <-chan Time r runtimeTimer } ~~~ Timer只有兩個成員: * C: 管道,上層應用根據此管道接收事件; * r: runtime定時器,該定時器即系統管理的定時器,對上層應用不可見; 這里應該按照層次來理解Timer數據結構,Timer.C即面向Timer用戶的,Timer.r是面向底層的定時器實現 系統協程把runtimeTimer存放在數組中,并按照`when`字段對所有的runtimeTimer進行堆排序,定時器觸發時執行runtimeTimer中的預定義函數`f`,即完成了一次定時任務 ### runtimeTimer 前面我們說過,創建一個Timer實質上是把一個定時任務交給專門的協程進行監控,這個任務的載體便是`runtimeTimer`,簡單的講,每創建一個Timer意味著創建一個runtimeTimer變量,然后把它交給系統進行監控。我們通過設置runtimeTimer過期后的行為來達到定時的目的。 源碼包`src/time/sleep.go:runtimeTimer`定義了其數據結構: ~~~go type runtimeTimer struct { tb uintptr // 存儲當前定時器的數組地址 i int // 存儲當前定時器的數組下標 when int64 // 當前定時器觸發時間 period int64 // 當前定時器周期觸發間隔 f func(interface{}, uintptr) // 定時器觸發時執行的函數 arg interface{} // 定時器觸發時執行函數傳遞的參數一 seq uintptr // 定時器觸發時執行函數傳遞的參數二(該參數只在網絡收發場景下使用) } ~~~ 其成員如下: * tb: 系統底層存儲runtimeTimer的數組地址; * i: 當前runtimeTimer在tb數組中的下標; * when: 定時器觸發事件的時間; * period: 定時器周期性觸發間隔(對于Timer來說,此值恒為0); * f: 定時器觸發時執行的回調函數,回調函數接收兩個參數; * arg: 定時器觸發時執行回調函數的參數一; * seq: 定時器觸發時執行回調函數的參數二(Timer并不使用該參數); ### 創建Timer 我們來看創建Timer的實現,非常簡單: ~~~go func NewTimer(d Duration) *Timer { c := make(chan Time, 1) // 創建一個管道 t := &Timer{ // 構造Timer數據結構 C: c, // 新創建的管道 r: runtimeTimer{ when: when(d), // 觸發時間 f: sendTime, // 觸發后執行函數sendTime arg: c, // 觸發后執行函數sendTime時附帶的參數 }, } startTimer(&t.r) // 此處啟動定時器,只是把runtimeTimer放到系統協程的堆中,由系統協程維護 return t } ~~~ NewTimer()只是構造了一個Timer,然后把Timer.r通過startTimer()交給系統協程維護。 其中when()方法是計算下一次定時器觸發的絕對時間,即當前時間+NewTimer()參數d。 其中sendTime()方法便是定時器觸發時的動作: ~~~go func sendTime(c interface{}, seq uintptr) { select { case c.(chan Time) <- Now(): default: } } ~~~ sendTime接收一個管道作為參數,其主要任務是向管道中寫入當前時間。 創建Timer時生成的管道含有一個緩沖區(`make(chan Time, 1)`),所以Timer觸發時向管道寫入時間永遠不會阻塞,sendTime寫完即退出。 之所以sendTime()使用select并搭配一個空的default分支,是因為后面所要講的Ticker也復用sendTime(),Ticker觸發時也會向管道中寫入時間,但無法保證之前的數據已被取走,所以使用select并搭配一個空的default分支,確保sendTime()不會阻塞,Ticker觸發時,如果管道中還有值,則本次不再向管道中寫入時間,本次觸發的事件直接丟棄。 `startTimer(&t.r)`的具體實現在runtime包,其主要作用是把runtimeTimer寫入到系統協程的數組中,并啟動系統協程(如果系統協程還未開始運行的話)。更詳細的內容,待后面講解系統協程時再介紹。 綜上,創建一個Timer示意圖如下: ![](https://img.kancloud.cn/d6/b2/d6b2692d6679f403a8b26208c3b540a1_770x323.png) ### 停止Timer 停止Timer,只是簡單的把Timer從系統協程中移除。函數主要實現如下: ~~~go func (t *Timer) Stop() bool { return stopTimer(&t.r) } ~~~ stopTimer()即通知系統協程把該Timer移除,即不再監控。系統協程只是移除Timer并不會關閉管道,以避免用戶協程讀取錯誤。 系統協程監控Timer是否需要觸發,Timer觸發后,系統協程會刪除該Timer。所以在Stop()執行時有兩種情況: * Timer還未觸發,系統協程已經刪除該Timer,Stop()返回false; * Timer已經觸發,系統協程還未刪除該Timer,Stop()返回true; 綜上,停止一個Timer示意圖如下: ![](https://img.kancloud.cn/1e/24/1e2439e2044a3a9c5f72fd4a5c7756b0_770x323.png) ### 重置Timer 重置Timer時會先把timer從系統協程中刪除,修改新的時間后重新添加到系統協程中。 重置函數主要實現如下所示: ~~~go func (t *Timer) Reset(d Duration) bool { w := when(d) active := stopTimer(&t.r) t.r.when = w startTimer(&t.r) return active } ~~~ 其返回值與Stop()保持一致,即如果Timer成功停止,則返回true,如果Timer已經觸發,則返回false。 重置一個Timer示意圖如下: ![](https://img.kancloud.cn/da/96/da96de8eff45b6c202eb8d11fc83e9ff_770x323.png) 由于新加的Timer時間很可能變化,所以其在系統協程的位置也會發生變化。 需要注意的是,按照官方說明,Reset()應該作用于已經停掉的Timer或者已經觸發的Timer,按照這個約定其返回值將總是返回false,之所以仍然保留是為了保持向前兼容,使用老版本Go編寫的應用不需要因為Go升級而修改代碼。 如果不按照此約定使用Reset(),有可能遇到Reset()和Timer觸發同時執行的情況,此時有可能會收到兩個事件,從而對應用程序造成一些負面影響,使用時一定要注意。 ***** 【總結】 * NewTimer()創建一個新的Timer交給系統協程監控; * Stop()通知系統協程刪除指定的Timer; * Reset()通知系統協程刪除指定的Timer并再添加一個新的Timer;
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看