Go?Ticker?周期性定時器用法及實現(xiàn)原理詳解
前言
定時器在Go語言應用中使用非常廣泛,Go語言的標準庫里提供兩種類型的計時器,一種是一次性的定時器Timer,另外一種是周期性的定時器Ticker。本文主要來看一下Ticker的用法和實現(xiàn)原理,需要的朋友可以參考以下內(nèi)容,希望對大家有幫助。
Ticker
Ticker是周期性定時器,即周期性的觸發(fā)一個事件,它會以一個間隔(interval)往channel發(fā)送一個事件(當前時間),而channel的接收者可以以固定的時間間隔從channel中讀取事件。通過Ticker本身提供的管道將事件傳遞出去。
應用示例
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(time.Second * 1) //創(chuàng)建一個周期性定時器
i := 1
for {
fmt.Println(i, "====>", <-ticker.C)
if i == 5 {
ticker.Stop() //停止定時器
break
}
i++
}
}
輸出結(jié)果:
1 ====> 2022-08-24 15:58:38.971837 +0800 CST m=+1.001366085
2 ====> 2022-08-24 15:58:39.971154 +0800 CST m=+2.000695418
3 ====> 2022-08-24 15:58:40.971633 +0800 CST m=+3.001185460
4 ====> 2022-08-24 15:58:41.97109 +0800 CST m=+4.000654126
5 ====> 2022-08-24 15:58:42.971594 +0800 CST m=+5.001169210
創(chuàng)建定時器
使用NewTicker()方法就可以創(chuàng)建一個周期性定時器,函數(shù)如下:
func NewTicker(d Duration) *Ticker
其中參數(shù)d即為定時器時間觸發(fā)的周期,為一個時間段。
停止定時器
使用定時器對外暴露的 Stop 方法就可以停掉一個周期性定時器, 函數(shù)如下:
func (t *Ticker) Stop()
該方法會停止計時,停止后不會向定時器的管道中寫入事件,但管道并不會被關閉。
管道在使用完成后,生命周期結(jié)束后會自動釋放。
實現(xiàn)原理
數(shù)據(jù)結(jié)構(gòu)
Ticker的數(shù)據(jù)結(jié)構(gòu)與Timer完全一致:
通過src/time.sleep.go:Ticker定義了Timer數(shù)據(jù)結(jié)構(gòu):
type Ticker struct {
C <-chan Time
r runtimeTimer
}
它提供了一個channel,在定時時間到達之前,沒有數(shù)據(jù)寫入Ticker.C會一直阻塞,直到時間到達,向channel寫入系統(tǒng)時間,阻塞解除,可以從中讀取數(shù)據(jù),這就是一個事件。
我們可以理解為Ticker.C即面向Ticker用戶的,Ticker.r是面向底層的定時器實現(xiàn)。
runtimeTimer
runtimeTimer與Timer一樣,任務的載體,用于監(jiān)控定時任務,每創(chuàng)建一個Timer就創(chuàng)建一個runtimeTimer變量,然后把它交給系統(tǒng)進行監(jiān)控,我們通過設置runtimeTimer過期后的行為來達到定時的目的。
源碼包src/time/sleep.go:runtimeTimer定義了其數(shù)據(jù)結(jié)構(gòu):
type runtimeTimer struct {
tb uintptr // 存儲當前定時器的數(shù)組地址
i int // 存儲當前定時器的數(shù)組下標
when int64 // 當前定時器觸發(fā)時間
period int64 // 當前定時器周期觸發(fā)間隔
f func(interface{}, uintptr) // 定時器觸發(fā)時執(zhí)行的函數(shù)
arg interface{} // 定時器觸發(fā)時執(zhí)行函數(shù)傳遞的參數(shù)一
seq uintptr // 定時器觸發(fā)時執(zhí)行函數(shù)傳遞的參數(shù)二(該參數(shù)只在網(wǎng)絡收發(fā)場景下使用)
}
創(chuàng)建Ticker
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), // Ticker跟Timer的重要區(qū)就是提供了period這個參數(shù),據(jù)此決定timer是一次性的,還是周期性的
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}
NewTicker()構(gòu)造了一個Ticker,然后把Ticker.r通過startTimer()交給系統(tǒng)協(xié)程維護。
其中period為事件觸發(fā)的周期。
停止Ticker
停止Ticker,只是把Ticker從系統(tǒng)協(xié)程中移除。
func (t *Ticker) Stop() {
stopTimer(&t.r)
}
stopTicker()即通知系統(tǒng)協(xié)程把該Ticker移除,即不再監(jiān)控。系統(tǒng)協(xié)程只是移除Ticker并不會關閉管道,以避免用戶協(xié)程讀取錯誤。
注意:
Ticker在使用完后務必要釋放,否則會產(chǎn)生資源泄露,進而會持續(xù)消耗CPU資源,最后會把CPU耗盡。
ticker := time.NewTicker(1 * time.Second) defer ticker.Stop()
Ticker 與 Timer 區(qū)別
- Ticker —— 重復性執(zhí)行任務非常有用呢
- Timer —— 用于執(zhí)行一次性任務
小結(jié)
Ticker相關內(nèi)容總結(jié)如下:
- 使用time.NewTicker()來創(chuàng)建一個定時器;
- 使用Stop()來停止一個定時器;
- 定時器使用完畢要釋放,否則會產(chǎn)生資源泄露;
如果需要了解Timer,可以看這篇文章 http://www.dbjr.com.cn/article/260598.htm
以上就是Go Ticker 周期性定時器用法及實現(xiàn)原理詳解的詳細內(nèi)容,更多關于Go Ticker周期性定時器的資料請關注腳本之家其它相關文章!
相關文章
Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權詳解
最近項目中需要用到鑒權機制,golang中jwt可以用,這篇文章主要給大家介紹了關于Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權的相關資料,需要的朋友可以參考下2022-09-09
golang中set數(shù)據(jù)結(jié)構(gòu)的使用示例
本文主要介紹了golang中set數(shù)據(jù)結(jié)構(gòu)的使用示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03
golang連接MongoDB數(shù)據(jù)庫及數(shù)據(jù)庫操作指南
MongoDB是Nosql中常用的一種數(shù)據(jù)庫,下面這篇文章主要給大家介紹了關于golang連接MongoDB數(shù)據(jù)庫及數(shù)據(jù)庫操作的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-09-09

