91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang定時器Timer的用法和實現原理是什么

發布時間:2023-04-12 17:47:25 來源:億速云 閱讀:120 作者:iii 欄目:開發技術

本篇內容介紹了“golang定時器Timer的用法和實現原理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    Timer

    Timer是一種單一事件的定時器,即經過指定的時間后觸發一個事件,因為Timer只執行一次就結束,所以稱為單一事件,這個事件通過其本身提供的channel進行通知觸發。

    timer結構體

    通過src/time.sleep.go:Timer定義了Timer數據結構:

    // Timer代表一次定時,時間到達后僅執行一個事件。
    type Timer struct {
        C <-chan Time
        r runtimeTimer
    }

    它提供了一個channel,在定時時間到達之前,沒有數據寫入timer.C會一直阻塞,直到時間到達,向channel寫入系統時間,阻塞解除,可以從中讀取數據,這就是一個事件。

    創建定時器
    func NewTimer(d Duration) *Timer

    通過上面方法指定一個事件即可創建一個Timer,Timer一經創建便開始計時,不需要額外的啟動命令。

    示例:

    func main()  {
    	timer := time.NewTimer(time.Second * 5) //設置超時時間5s
    
    	<- timer.C
    	fmt.Println("Time out!")
    }
    停止定時器

    Timer創建后可以隨時停止,停止計時器的方法如下:

    func (t *Timer) Stop() bool

    其返回值代表定時器有沒有超時:

    • true:定時器超時前停止,后續不會再有事件發送。

    • false:定時器超時后停止。

    示例:

    func main()  {
    	timer := time.NewTimer(time.Second * 5) //設置超時時間5s
        timer.Stop()
    }
    重置定時器

    已經過期的定時器或者已停止的定時器,可以通過重置動作重新激活,方法如下:

    func (t *Timer) Reset(d Duration) bool

    重置的動作本質上是先停掉定時器,再啟動,其返回值也即是停掉計時器的返回值。

    func main()  {
    	timer := time.NewTimer(time.Second * 5)
    
    	<- timer.C
    	fmt.Println("Time out!")
    
    	timer.Stop() 
    	timer.Reset(time.Second*3)  // 重置定時器
    }

    實現原理

    每個Go應用程序都有一個協程專門負責管理所有的Timer,這個協程負責監控Timer是否過期,過期后執行一個預定義的動作,這個動作對于Timer而言就是發送當前時間到管道中。

    數據結構
    type Timer struct {
        C <-chan Time
        r runtimeTimer
    }

    Timer只有兩個成員:

    • C:channel,上層應用根據此管道接收事件;

    • r:runtimeTimer定時器,該定時器即系統管理的定時器,上層應用不可見。

    runtimeTimer

    任務的載體,用于監控定時任務,每創建一個Timer就創建一個runtimeTimer變量,然后把它交給系統進行監控,我們通過設置runtimeTimer過期后的行為來達到定時的目的。

    源碼包src/time/sleep.go:runtimeTimer定義了其數據結構:

    type runtimeTimer struct {
        tb uintptr                          // 存儲當前定時器的數組地址
        i  int                              // 存儲當前定時器的數組下標
    
        when   int64                        // 當前定時器觸發時間
        period int64                        // 當前定時器周期觸發間隔
        f      func(interface{}, uintptr)   // 定時器觸發時執行的函數
        arg    interface{}                  // 定時器觸發時執行函數傳遞的參數一
        seq    uintptr                      // 定時器觸發時執行函數傳遞的參數二(該參數只在網絡收發場景下使用)
    }
    創建Timer

    源碼實現:

    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()交給系統協程維護。

    • C 是一個帶1個容量的chan,這樣做有什么好處呢,原因是chan 無緩沖發送數據就會阻塞,阻塞系統協程,這顯然是不行的。

    • 回調函數設置為sendTime,執行參數為channelsendTime就是到點往C 里面發送當前時間的函數

    sendTime實現:

    //c interface{} 就是NewTimer 賦值的參數,就是channel
    func sendTime(c interface{}, seq uintptr) {
        select {
        case c.(chan Time) <- Now(): //寫不進去的話,C 已滿,走default 分支
        default:
        }
    }
    停止Timer

    停止Timer,就是把Timer從系統協程中移除。函數主要實現如下:

    func (t *Timer) Stop() bool {
        return stopTimer(&t.r)
    }

    stopTimer()即通知系統協程把該Timer移除,即不再監控。系統協程只是移除Timer并不會關閉管道,以避免用戶協程讀取錯誤。

    重置Timer

    重置Timer時會先把timer從系統協程中刪除,修改新的時間后重新添加到系統協程中。

    func (t *Timer) Reset(d Duration) bool {
        w := when(d)
        active := stopTimer(&t.r)
        t.r.when = w
        startTimer(&t.r)
        return active
    }

    補充:golang定時器Ticker

    time包下有一個Ticker結構體

    // Ticker保管一個通道,并每隔一段時間向其傳遞"tick"。
    type Ticker struct {
    	C <-chan Time // 周期性傳遞時間信息的通道.
    	r runtimeTimer
    }
    func NewTicker(d Duration) *Ticker{}

    NewTicker返回一個新的Ticker,該Ticker包含一個通道字段,并會每隔時間段d,就向該通道發送當時的時間。它會調整時間間隔或者丟棄tick信息以適應反應慢的接收者。如果d<=0會panic。關閉該Ticker可以釋放相關資源。

    func (t *Ticker) Stop()

    Stop關閉一個Ticker。在關閉后,將不會發送更多的tick信息。Stop不會關閉通道t.C,以避免從該通道的讀取不正確的成功。

    例子

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	t := time.NewTicker(5 * time.Second) //創建定時器
    	defer t.Stop()
        
    	go sync(t)
    	select {
    
    	}
    }
    
    func sync(t *time.Ticker) {
    	for {
    		// 每5秒中從chan t.C 中讀取一次
    		<-t.C
    		fmt.Println("執行數據備份任務:", time.Now().Format("2006-01-02 15:04:05"))
    	}
    }

    “golang定時器Timer的用法和實現原理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    澄城县| 漳浦县| 登封市| 博白县| 三门县| 通榆县| 大同市| 化隆| 搜索| 专栏| 盐津县| 漯河市| 乡城县| 白玉县| 浮梁县| 咸阳市| 祁东县| 正蓝旗| 德昌县| 南开区| 文水县| 抚顺市| 海宁市| 石首市| 原阳县| 洛阳市| 丰县| 上栗县| 阿拉善盟| 开鲁县| 阿拉尔市| 绥江县| 社旗县| 富锦市| 沙河市| 贵德县| 江达县| 光泽县| 金秀| 马山县| 准格尔旗|