淺析go中Ticker,Timer和Tick的用法與區(qū)別
寫(xiě)在前面
在go面試的時(shí)候,面試官經(jīng)常會(huì)問(wèn)time包的Ticker,Timer以及Tick的區(qū)別,一般在超時(shí)控制的時(shí)候用的比較多。今天就來(lái)詳細(xì)學(xué)一下這幾個(gè)的區(qū)別
Ticker
Ticker是周期性定時(shí)器,即周期性的觸發(fā)一個(gè)事件,它會(huì)以一個(gè)間隔(interval)往channel發(fā)送一個(gè)事件(當(dāng)前時(shí)間),而channel的接收者可以以固定的時(shí)間間隔從channel中讀取事件。通過(guò)Ticker本身提供的管道將事件傳遞出去
示例
func main() { t1 := time.NewTicker(3 * time.Second) defer t1.Stop() for { select { case <-t1.C: fmt.Printf("%s\n", time.Now()) } } }
結(jié)果
2023-10-21 18:53:30.629901 +0800 CST m=+3.001061072
2023-10-21 18:53:33.629444 +0800 CST m=+6.000526969
2023-10-21 18:53:36.629429 +0800 CST m=+9.000436237
通過(guò)NewTicker
創(chuàng)建一個(gè)Ticker,然后通過(guò)通過(guò)for+select實(shí)現(xiàn)定時(shí)執(zhí)行。記住Ticker一定要調(diào)用Stop
方法,關(guān)閉chan,否則容易造成內(nèi)存泄露。Ticker最常用的2個(gè)函數(shù)就是NewTicker
和Stop
。
Ticker
主要用于定期循環(huán)執(zhí)行某一個(gè)操作。
Timer
用于執(zhí)行一次性任務(wù)。在指定時(shí)間間隔之后再下chan發(fā)送一個(gè)事件(當(dāng)前時(shí)間)
func main() { t1 := time.NewTimer(3 * time.Second) defer t1.Stop() for { t1.Reset(3 * time.Second) select { case <-t1.C: fmt.Printf("%s\n", time.Now()) } } }
用Timer也能實(shí)現(xiàn)Ticker循環(huán)執(zhí)行的功能,但是每次必須調(diào)用Reset
方法,否則會(huì)死鎖,因?yàn)門(mén)imer只會(huì)執(zhí)行一次。不過(guò)Timer一般不用于循環(huán)執(zhí)行,它用于超時(shí)控制,比如調(diào)用某個(gè)rpc,如果超過(guò)3s則終止調(diào)用。
示例
func main() { t1 := time.NewTimer(3 * time.Second) defer t1.Stop() ctx, cancel := mockRPC() select { case <-ctx.Done(): fmt.Printf("rpc end\n") break case <-t1.C: // t1時(shí)間到了,rpc還沒(méi)執(zhí)行完,則執(zhí)行cancel()并退出 fmt.Printf("%s\n", time.Now()) cancel() } } // mockRPC. 異步執(zhí)行5s鐘,如果已經(jīng)結(jié)束了則停止執(zhí)行 func mockRPC() (context.Context, context.CancelFunc) { ctx, cancel := context.WithCancel(context.Background()) go func() { for i := 0; i < 5; i++ { select { case <-ctx.Done(): break default: fmt.Printf("%d\n", i) time.Sleep(time.Second) } } }() return ctx, cancel }
結(jié)果
0
1
2
2023-10-21 19:18:53.565153 +0800 CST m=+3.000558307
Tick
Tick其實(shí)最簡(jiǎn)單,直接看它的源代碼
func Tick(d Duration) <-chan Time { if d <= 0 { return nil } return NewTicker(d).C }
發(fā)現(xiàn)Tick其實(shí)就是一個(gè)Ticker的C,所以使用起來(lái)更方便
func main() { t1 := time.Tick(3 * time.Second) for { select { case <-t1: fmt.Printf("%s\n", time.Now()) } } }
但是有一個(gè)問(wèn)題,由于Tick()
函數(shù)沒(méi)有返回Ticker,我們無(wú)法關(guān)閉它,所以這個(gè)t1
對(duì)應(yīng)的Ticker用于無(wú)法關(guān)閉,會(huì)造成內(nèi)存泄露。一般不推薦用Tick,直接使用Ticker就好了。應(yīng)該只能在程序結(jié)束的時(shí)候會(huì)回收內(nèi)存,但是Tick和Ticker區(qū)別這么小,不知道為什么要定義Tick()
這個(gè)函數(shù)。
總結(jié)
- Ticker是一個(gè)定時(shí)器。
- Timer是一個(gè)延遲執(zhí)行器,也可以通過(guò)
Reset()
來(lái)實(shí)現(xiàn)定時(shí)器。 - Tick()是一個(gè)函數(shù),返回Ticker的chan,不推薦使用。
到此這篇關(guān)于淺析go中Ticker,Timer和Tick的用法與區(qū)別的文章就介紹到這了,更多相關(guān)go Ticker Timer Tick內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go標(biāo)準(zhǔn)庫(kù)日志打印及同時(shí)輸出到控制臺(tái)與文件
Go語(yǔ)言內(nèi)置的log包實(shí)現(xiàn)了簡(jiǎn)單的日志服務(wù),下面這篇文章主要給大家介紹了關(guān)于Go標(biāo)準(zhǔn)庫(kù)日志打印及同時(shí)輸出到控制臺(tái)與文件的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11golang協(xié)程關(guān)閉踩坑實(shí)戰(zhàn)記錄
協(xié)程(coroutine)是Go語(yǔ)言中的輕量級(jí)線程實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于golang協(xié)程關(guān)閉踩坑的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03Go Sentinel 動(dòng)態(tài)數(shù)據(jù)源配置指南(示例詳解)
本文介紹了如何使用Go語(yǔ)言配置Sentinel的動(dòng)態(tài)數(shù)據(jù)源,并通過(guò)本地文件和Nacos兩種方式實(shí)現(xiàn)動(dòng)態(tài)配置,通過(guò)這種方式,可以靈活地管理和更新限流規(guī)則,提升系統(tǒng)的穩(wěn)定性和響應(yīng)速度,感興趣的朋友跟隨小編一起看看吧2025-01-01Go語(yǔ)言{}大括號(hào)的特殊用法實(shí)例探究
這篇文章主要為大家介紹了Go語(yǔ)言{}大括號(hào)的特殊用法實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01golang并發(fā)執(zhí)行的幾種方式小結(jié)
本文主要介紹了golang并發(fā)執(zhí)行的幾種方式小結(jié),主要包括了Channel,WaitGroup ,Context,使用這三種機(jī)制中的一種或者多種可以達(dá)到并發(fā)控制很好的效果,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08