Go Timer使用方法
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
簡(jiǎn)介
Timer實(shí)際上是一種單一事件的定時(shí)器,即經(jīng)過(guò)指定的時(shí)間后觸發(fā)一個(gè)事件,這個(gè)事件通過(guò)其本身提供的channel進(jìn)行通知。之所以叫單一事件,是因?yàn)門imer只執(zhí)行一次就結(jié)束,這也是Timer與Ticker的最重要的區(qū)別之一。
通過(guò)timer.NewTimer(d Duration)可以創(chuàng)建一個(gè)timer,參數(shù)即等待的時(shí)間,時(shí)間到來(lái)后立即觸發(fā)一個(gè)事件。
源碼包src/time/sleep.go:Timer定義了Timer數(shù)據(jù)結(jié)構(gòu):
type Timer struct { // Timer代表一次定時(shí),時(shí)間到來(lái)后僅發(fā)生一個(gè)事件。C <-chan Timer runtimeTimer }Timer對(duì)外僅暴露一個(gè)channel,指定的時(shí)間到來(lái)時(shí)就往該channel中寫入系統(tǒng)時(shí)間,也即一個(gè)事件。
本節(jié)我們介紹Timer的幾個(gè)使用場(chǎng)景,同時(shí)再介紹其對(duì)外呈現(xiàn)的方法。
使用場(chǎng)景
設(shè)定超時(shí)時(shí)間
有時(shí)我們希望從一個(gè)管道中讀取數(shù)據(jù),在管道中沒(méi)有數(shù)據(jù)時(shí),我們不想讓程序永遠(yuǎn)阻塞在管道中,而是設(shè)定一個(gè)超時(shí)時(shí)間,在此時(shí)間段中如果管道中還是沒(méi)有數(shù)據(jù)到來(lái),則判定為超時(shí)。
Go源碼包中有大量類似的用法,比如從一個(gè)連接中等待數(shù)據(jù),其簡(jiǎn)單的用法如下代碼所示:
func WaitChannel(conn <-chan string) bool {timer := time.NewTimer(1 * time.Second)select {case <- conn:timer.Stop()return truecase <- timer.C: // 超時(shí)println("WaitChannel timeout!")return false} }WaitChannel作用就是檢測(cè)指定的管道中是否有數(shù)據(jù)到來(lái),通過(guò)select語(yǔ)句輪詢conn和timer.C兩個(gè)管道,timer會(huì)在1s后向timer.C寫入數(shù)據(jù),如果1s內(nèi)conn還沒(méi)有數(shù)據(jù),則會(huì)判斷為超時(shí)。
延遲執(zhí)行某個(gè)方法
有時(shí)我們希望某個(gè)方法在今后的某個(gè)時(shí)刻執(zhí)行,如下代碼所示:
func DelayFunction() {timer := time.NewTimer(5 * time.Second)select {case <- timer.C:log.Println("Delayed 5s, start to do something.")} }DelayFunction()會(huì)一直等待timer的事件到來(lái)才會(huì)執(zhí)行后面的方法(打印)。
Timer對(duì)外接口
創(chuàng)建定時(shí)器
使用方法func NewTimer(d Duration) *Timer指定一個(gè)時(shí)間即可創(chuàng)建一個(gè)Timer,Timer一經(jīng)創(chuàng)建便開(kāi)始計(jì)時(shí),不需要額外的啟動(dòng)命令。
實(shí)際上,創(chuàng)建Timer意味著把一個(gè)計(jì)時(shí)任務(wù)交給系統(tǒng)守護(hù)協(xié)程,該協(xié)程管理著所有的Timer,當(dāng)Timer的時(shí)間到達(dá)后向Timer的管道中發(fā)送當(dāng)前的時(shí)間作為事件。詳細(xì)的實(shí)現(xiàn)原理我們后面會(huì)單獨(dú)介紹。
停止定時(shí)器
Timer創(chuàng)建后可以隨時(shí)停止,停止計(jì)時(shí)器的方法是:
func (t *Timer) Stop() bool其返回值代表定時(shí)器有沒(méi)有超時(shí):
- true: 定時(shí)器超時(shí)前停止,后續(xù)不會(huì)再有事件發(fā)送;
- false: 定時(shí)器超時(shí)后停止;
實(shí)際上,停止計(jì)時(shí)器意味著通知系統(tǒng)守護(hù)協(xié)程移除該定時(shí)器。詳細(xì)的實(shí)現(xiàn)原理我們后面單獨(dú)介紹。
重置定時(shí)器
已過(guò)期的定時(shí)器或者已停止的定時(shí)器,可以通過(guò)重置動(dòng)作重新激活,重置方法如下:
func (t *Timer) Reset(d Duration) bool重置的動(dòng)作實(shí)質(zhì)上是先停掉定時(shí)器,再啟動(dòng)。其返回值也即停掉計(jì)時(shí)器的返回值。
需要注意的是,重置定時(shí)器雖然可以用于修改還未超時(shí)的定時(shí)器,但正確的使用方式還是針對(duì)已過(guò)期的定時(shí)器或已被停止的定時(shí)器,同時(shí)其返回值也不可靠,返回值存在的價(jià)值僅僅是與前面版本兼容。
實(shí)際上,重置定時(shí)器意味著通知系統(tǒng)守護(hù)協(xié)程移除該定時(shí)器,重新設(shè)定時(shí)間后,再把定時(shí)器交給守護(hù)協(xié)程。詳細(xì)的實(shí)現(xiàn)原理我們后面單獨(dú)介紹。
簡(jiǎn)單接口
前面介紹了Timer的標(biāo)準(zhǔn)接口,time包同時(shí)還提供了一些簡(jiǎn)單的方法,在特定的場(chǎng)景下可以簡(jiǎn)化代碼。
After()
有時(shí)我們就是想等指定的時(shí)間,沒(méi)有需求提前停止定時(shí)器,也沒(méi)有需求復(fù)用該定時(shí)器,那么可以使用匿名的定時(shí)器。
func After(d Duration) <-chan Time方法創(chuàng)建一個(gè)定時(shí)器,并返回定時(shí)器的管道,如下代碼所示:
func AfterDemo() {log.Println(time.Now())<- time.After(1 * time.Second)log.Println(time.Now()) }AfterDemo()兩條打印時(shí)間間隔為1s,實(shí)際還是一個(gè)定時(shí)器,但代碼變得更簡(jiǎn)潔。
AfterFunc()
前面我們例子中講到延遲一個(gè)方法的調(diào)用,實(shí)際上通過(guò)AfterFunc可以更簡(jiǎn)潔。AfterFunc的原型為:
func AfterFunc(d Duration, f func()) *Timer該方法在指定時(shí)間到來(lái)后會(huì)執(zhí)行函數(shù)f。例如:
func AfterFuncDemo() {log.Println("AfterFuncDemo start: ", time.Now())time.AfterFunc(1 * time.Second, func() {log.Println("AfterFuncDemo end: ", time.Now())})time.Sleep(2 * time.Second) // 等待協(xié)程退出 }AfterFuncDemo()中先打印一個(gè)時(shí)間,然后使用AfterFunc啟動(dòng)一個(gè)定器,并指定定時(shí)器結(jié)束時(shí)執(zhí)行一個(gè)方法打印結(jié)束時(shí)間。
與上面的例子所不同的是,time.AfterFunc()是異步執(zhí)行的,所以需要在函數(shù)最后sleep等待指定的協(xié)程退出,否則可能函數(shù)結(jié)束時(shí)協(xié)程還未執(zhí)行。
總結(jié)
本節(jié)簡(jiǎn)單介紹了Timer的常見(jiàn)使用場(chǎng)景和接口,后面的章節(jié)再介紹Ticker、以及二者的實(shí)際細(xì)節(jié)。
Timer內(nèi)容總結(jié)如下:
- time.NewTimer(d)創(chuàng)建一個(gè)Timer;
- timer.Stop()停掉當(dāng)前Timer;
- timer.Reset(d)重置當(dāng)前Timer;
贈(zèng)人玫瑰手留余香,如果覺(jué)得不錯(cuò)請(qǐng)給個(gè)贊~
本篇文章已歸檔到GitHub項(xiàng)目,求星~ 點(diǎn)我即達(dá)
轉(zhuǎn)載于:https://my.oschina.net/renhc/blog/3026957
總結(jié)
以上是生活随笔為你收集整理的Go Timer使用方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android如何编译出带符号表的.so
- 下一篇: 中台之上(十五):被忽视的产品目录