Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例
開門見山寫一個(gè)
package main import ( "fmt" "github.com/robfig/cron" "log" "strings" "time" ) func CronTask() { log.Println("******** ******* *******") } func CronTest() { log.Println("Starting Cron...") c := cron.New() c.AddFunc("* * * * * *", CronTask) //2 * * * * *, 2 表示每分鐘的第2s執(zhí)行一次 c.Start() t1 := time.NewTimer(time.Second * 10) // ?time.Second * 10 啥意思? *100行嗎? for { select { case <-t1.C: fmt.Println("Time now:", time.Now().Format("2006-01-02 15:04:05")) // 為何要專門制定這個(gè)時(shí)間 t1.Reset(time.Second * 10) } } } func main() { fmt.Println(strings.Repeat("START ", 15)) CronTest() fmt.Println(strings.Repeat("END ", 15)) }
核心的定時(shí)器代碼就3行
c := cron.New() c.AddFunc("* * * * * *", CronTask) c.Start()
那后面那些代碼時(shí)作甚的?
一開始看到示例代碼時(shí),有個(gè)疑惑,如代碼中注釋
t1 := time.NewTimer(time.Second * 10)
這里time.Second*10是干啥的? 是否可以寫成*100呢, 改了后原來是可以的,那更疑惑了既然都行為啥還要寫個(gè)這個(gè)?
還有后面的for-select-case也是一臉懵逼~~~~
運(yùn)行代碼,從結(jié)果反推下原理吧,一次執(zhí)行結(jié)果
START START START START START START START START START START START START START START START
2020/05/01 07:38:07 Starting Cron...
2020/05/01 07:38:08 ******** ******* *******
2020/05/01 07:38:09 ******** ******* *******
2020/05/01 07:38:10 ******** ******* *******
2020/05/01 07:38:11 ******** ******* *******
2020/05/01 07:38:12 ******** ******* *******
2020/05/01 07:38:13 ******** ******* *******
2020/05/01 07:38:14 ******** ******* *******
2020/05/01 07:38:15 ******** ******* *******
2020/05/01 07:38:16 ******** ******* *******
2020/05/01 07:38:17 ******** ******* *******
Time now: 2020-05-01 07:38:17
2020/05/01 07:38:18 ******** ******* *******
2020/05/01 07:38:19 ******** ******* *******
2020/05/01 07:38:20 ******** ******* *******
2020/05/01 07:38:21 ******** ******* *******
2020/05/01 07:38:22 ******** ******* *******
2020/05/01 07:38:23 ******** ******* *******
2020/05/01 07:38:24 ******** ******* *******
2020/05/01 07:38:25 ******** ******* *******
2020/05/01 07:38:26 ******** ******* *******
2020/05/01 07:38:27 ******** ******* *******
Time now: 2020-05-01 07:38:27
2020/05/01 07:38:28 ******** ******* *******
以上是運(yùn)行的片段,有兩大發(fā)現(xiàn)
- 有START START START。。。沒有END END END 。。。。:說明了代碼在執(zhí)行時(shí)阻塞在定時(shí)器里,定時(shí)器沒有執(zhí)行完,永遠(yuǎn)不會(huì)執(zhí)行END
- Time now打出來的間隔正好是10s
哦,原來time.NewTimer是個(gè)定時(shí)器,當(dāng)這個(gè)時(shí)間間隔完了后再重新打開一個(gè)。for-select-case 這一塊目的是阻塞流程,不讓程序結(jié)束。 理解對嗎
如果是這樣,去掉for-select-case 執(zhí)行第一個(gè)定時(shí)器時(shí)也可以停10s,是這樣嗎?試驗(yàn)下:屏蔽掉for-select-case, 輸出
START START START START START START START START START START START START START START START
2020/05/01 07:56:22 Starting Cron...
END END END END END END END END END END END END END END END
打臉了,看來阻塞主要靠for-select-case實(shí)現(xiàn),那原理是什么呢?
去掉t1.Reset效果咋樣呢?
t1 := time.NewTimer(time.Second * 10) // ?time.Second * 10 啥意思? *100行嗎? for { fmt.Println("hihihihi") select { case <-t1.C: fmt.Println("hello") } }
輸出
START START START START START START START START START START START START START START START
2020/05/01 08:12:21 Starting Cron...
hihihihi
2020/05/01 08:12:22 ******** ******* *******
2020/05/01 08:12:23 ******** ******* *******
2020/05/01 08:12:24 ******** ******* *******
2020/05/01 08:12:25 ******** ******* *******
2020/05/01 08:12:26 ******** ******* *******
2020/05/01 08:12:27 ******** ******* *******
2020/05/01 08:12:28 ******** ******* *******
2020/05/01 08:12:29 ******** ******* *******
2020/05/01 08:12:30 ******** ******* *******
2020/05/01 08:12:31 ******** ******* *******
hello
hihihihi
2020/05/01 08:12:32 ******** ******* *******
2020/05/01 08:12:33 ******** ******* *******
2020/05/01 08:12:34 ******** ******* *******
2020/05/01 08:12:35 ******** ******* *******
2020/05/01 08:12:36 ******** ******* *******
更蒙了,去掉reset, 運(yùn)行完第一個(gè)定時(shí)器10s, 非但沒聽,還直接執(zhí)行起來了,沒停了
for 循環(huán)里的print不是刷刷的一大片,而是和case命中時(shí)一期打,看來是時(shí)候了解下select-case的原理了
select case
按慣例先上個(gè)例子
package main import ( "fmt" "strings" ) func SelectTest() { intChan := make(chan int, 1) stringChan := make(chan string, 1) intChan <- 123456 stringChan <- "hello" select { case value := <-intChan: fmt.Println(value) case value := <- stringChan: fmt.Println(value) } } func main() { fmt.Println(strings.Repeat("START ", 15)) SelectTest() fmt.Println(strings.Repeat("END ", 15)) }
執(zhí)行多次可以看到,輸出的結(jié)果是 123456、"hello"不定
select 語法
每個(gè)case都必須是個(gè)通信
如果一個(gè)通信可進(jìn)行它就執(zhí)行,其他被忽略
如果有多個(gè)case可執(zhí)行,就會(huì)隨機(jī)的選擇一個(gè)執(zhí)行
如果沒有case可執(zhí)行,如果如果有default,執(zhí)行default語句;否則就阻塞,直到有某個(gè)通信可行
這里還是有很多問題, 單開一節(jié)弄清楚 select語句
再回到一開始的定時(shí)任務(wù)
回顧正題,定時(shí)原理解析
t1 := time.NewTimer(time.Second * 10) for { select { case <-t1.C: fmt.Println("Time now:", time.Now().Format("2006-01-02 15:04:05")) t1.Reset(time.Second * 10) } }
- 生成一個(gè)定時(shí)器t1, 執(zhí)行for循環(huán),一開始定時(shí)時(shí)間(10s)未到, 也沒有阻塞任務(wù),它就阻塞在case中;
- 定時(shí)時(shí)間到了,則執(zhí)行case中語句;
- 然后又重新恢復(fù)定時(shí)時(shí)長
- 重新走for循環(huán),還是重復(fù)上面的故事
上面代碼中嘗試把case中的t1.Reset去掉,結(jié)果也是定時(shí)任務(wù)不同的執(zhí)行,原因是執(zhí)行case中的語句后,接著執(zhí)行for循環(huán),由于沒有新通信過來(case語句永遠(yuǎn)無法滿足),同時(shí)沒有default語句,所以同樣可以阻塞再次。
相比在case中t1 Reset, t1 Reset更靈活些,因?yàn)榭梢栽倜看沃匦聺M足case時(shí)做一些靈活的操作,比如跳出循環(huán),做一些統(tǒng)計(jì)打印等。
到此這篇關(guān)于Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Golang Cron 定時(shí)任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go可變參數(shù)函數(shù)的實(shí)現(xiàn)
可變參數(shù)函數(shù)是指函數(shù)參數(shù)的某個(gè)參數(shù)可有可無,即這個(gè)參數(shù)的個(gè)數(shù)可以為0會(huì)多個(gè),可變參數(shù)函數(shù)參數(shù)在日常編程中大量使用,本文主要介紹了Go可變參數(shù)函數(shù)的實(shí)現(xiàn),感興趣的可以了解一下2023-12-12深入探究Golang中l(wèi)og標(biāo)準(zhǔn)庫的使用
Go?語言標(biāo)準(zhǔn)庫中的?log?包設(shè)計(jì)簡潔明了,易于上手,可以輕松記錄程序運(yùn)行時(shí)的信息、調(diào)試錯(cuò)誤以及跟蹤代碼執(zhí)行過程中的問題等。本文主要來深入探究?log?包的使用和原理,幫助讀者更好地了解和掌握它2023-05-05gorm整合進(jìn)go-zero的實(shí)現(xiàn)方法
go-zero提供的代碼生成器里面,沒有提供orm框架操作,但是提供了遍歷的緩存操作,所以可以利用gorm當(dāng)作一個(gè)sql語句的生成器,把生成后的sql語句放到go-zero生成的模板中去執(zhí)行,對gorm整合進(jìn)go-zero的實(shí)現(xiàn)方法感興趣的朋友一起看看吧2022-03-03Go語言實(shí)現(xiàn)字符串搜索算法Boyer-Moore
Boyer-Moore?算法是一種非常高效的字符串搜索算法,被廣泛的應(yīng)用于多種字符串搜索場景,下面我們就來學(xué)習(xí)一下如何利用Go語言實(shí)現(xiàn)這一字符串搜索算法吧2023-11-11Go語言設(shè)計(jì)模式之實(shí)現(xiàn)觀察者模式解決代碼臃腫
今天學(xué)習(xí)一下用?Go?實(shí)現(xiàn)觀察者模式,觀察者模式主要是用來實(shí)現(xiàn)事件驅(qū)動(dòng)編程。事件驅(qū)動(dòng)編程的應(yīng)用還是挺廣的,除了我們都知道的能夠用來解耦:用戶修改密碼后,給用戶發(fā)短信進(jìn)行風(fēng)險(xiǎn)提示之類的典型場景,在微服務(wù)架構(gòu)實(shí)現(xiàn)最終一致性、實(shí)現(xiàn)事件源A?+?ES2022-08-08Go語言學(xué)習(xí)之接口類型(interface)詳解
接口是用來定義行為的類型,定義的行為不由接口直接實(shí)現(xiàn),而由通過方法由定義的類型實(shí)現(xiàn),本文就來和大家詳細(xì)講講Go語言中接口的使用吧2023-03-03Go語言實(shí)現(xiàn)管理多個(gè)數(shù)據(jù)庫連接
在軟件開發(fā)過程中,使用?MySQL、PostgreSQL?或其他數(shù)據(jù)庫是很常見的,由于配置和要求不同,管理這些連接可能具有挑戰(zhàn)性,下面就來和大家聊聊如何在Go中管理多個(gè)數(shù)據(jù)庫連接吧2023-10-10我放棄Python轉(zhuǎn)Go語言的9大理由(附優(yōu)秀書籍推薦)
這篇文章主要給大家介紹了關(guān)于我放棄Python轉(zhuǎn)Go語言的9大理由,以及給大家推薦了6本優(yōu)秀的go語言書籍,對同樣想學(xué)習(xí)golang的朋友們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10