作者:_AlphaBaby_
最開始接觸定時任務的概念是在大二的一個計算機作業系統設計的實驗課上,當時老師給了五個任務要求,自己任選三個小組完成。
依稀還記得當時有個作業的任務需要每隔一段時間就執行一次:上百度就了解到了這樣要給命令:crontab,這個命令可以設定在後臺定時跑一個腳本。
如果對這個命令比較感興趣或者有這樣一個需求,可以參考:在linux上定期執行命令、腳本(cron,crontab,anacron)
cron 功能
在Golang中也有這樣一個工具的封裝。提一下cron主要能幹什麼:
比如我們手機裡面設置的鬧鐘,我們可以設置成每天早上7:00,每周周一到周三晚上一點,我們可以把cron形象的看作一個鬧鐘,會在我們規定的時間自動執行一些我們設置好的動作。
作為一個大學生,你可能追求過某某女孩子,你可能有這樣一個需求:每天早上微信給她發早安和晚上給她發晚安。這可能是個不錯的點子。
這都是浮雲,還是努力學習,學會怎麼用才是關鍵,不然你也寫不出來。
cron 用法
首先先把第三方庫下載下來:
$ go get -v -u github.com/robfig/cron
我們來看一個小的demo:每隔一秒列印"hello world"
1package main 2 3import ( 4"log" 5 6"github.com/robfig/cron" 7) 8 9funcmain() {10 log.Println("Starting...")1112 c := cron.New() // 新建一個定時任務對象13 c.AddFunc("* * * * * *", func() {14 log.Println("hello world")15 }) // 給對象增加定時任務16 c.Start()17select {18 }19}
這個小功能用time.Ticker也可以實現,我們為什麼要使用cron來完成呢?別急接著往下面看就知道了。
cron表達式
我們在上面demo中使用了AddFunc,第一個參數我們傳遞了一個字符串是:"* * * * * *",這六個*是指什麼呢?
1 ┌─────────────second 範圍 (0 - 60) 2 │ ┌───────────── min (0 - 59) 3 │ │ ┌────────────── hour (0 - 23) 4 │ │ │ ┌─────────────── day of month (1 - 31) 5 │ │ │ │ ┌──────────────── month (1 - 12) 6 │ │ │ │ │ ┌───────────────── day of week (0 - 6) (0to6 are Sunday to 7 │ │ │ │ │ │ Saturday) 8 │ │ │ │ │ │ 9 │ │ │ │ │ │10 * * * * * *
匹配符號
星號(*) :表示 cron 表達式能匹配該欄位的所有值。如在第5個欄位使用星號(month),表示每個月斜線(/):表示增長間隔,如第2個欄位(minutes) 值是 3-59/15,表示每小時的第3分鐘開始執行一次,之後 每隔 15 分鐘執行一次(即 3(3+0*15)、18(3+1*15)、33(3+2*15)、48(3+3*15) 這些時間點執行),這裡也可以表示為:3/15逗號(,):用於枚舉值,如第6個欄位值是 MON,WED,FRI,表示 星期一、三、五 執行連字號(-):表示一個範圍,如第3個欄位的值為 9-17 表示 9am 到 5pm 直接每個小時(包括9和17)問號(?):只用於 日(Day of month) 和 星期(Day of week),表示不指定值,可以用於代替 *
example
比如我們的手機卡假設都是在每個月的開始時間就更新資費:
"0 0 0 1 * *" // 表示每個月1號的00:00:00"0 1 1 1 * *" // 表示每個月1號的01:01:00
每隔5秒執行一次:"*/5 * * * * ?"每隔1分鐘執行一次:"0 */1 * * * ?"每天23點執行一次:"0 0 23 * * ?"每天凌晨1點執行一次:"0 0 1 * * ?"每月1號凌晨1點執行一次:"0 0 1 1 * ?"在26分、29分、33分執行一次:"0 26,29,33 * * * ?"每天的0點、13點、18點、21點都執行一次:"0 0 0,13,18,21 * * ?"
pre-defined schedules
github.com/robfig/cron 包還給我門提供了一些預定義的模式:
EntryDescriptionEquivalent To@yearly (or @annually)Run once a year, midnight, Jan. 1st0 0 0 1 1 *@monthlyRun once a month, midnight, first of month0 0 0 1 * *@weeklyRun once a week, midnight between Sat/Sun0 0 0 * * 0@daily (or @midnight)Run once a day, midnight0 0 0 * * *@hourlyRun once an hour, beginning of hour0 0 * * * *@every <duration>every duration
1c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
golang cron主要的設計思路
主要類型或接口說明(借用大佬)
Cron:包含一系列要執行的實體;支持暫停【stop】;添加實體等1type Cron struct {2 entries []*Entry3 stop chanstruct{} // 控制 Cron 實例暫停4 add chan *Entry // 當 Cron 已經運行了,增加新的 Entity 是通過 add 這個 channel 實現的5 snapshot chan []*Entry // 獲取當前所有 entity 的快照6 running bool// 當已經運行時為true;否則為false7}
注意,Cron 結構沒有導出任何成員。注意:有一個成員 stop,類型是 struct{},即空結構體。
Entry:調度實體
1type Entry struct { 2// The schedule on which this job should be run. 3// 負責調度當前 Entity 中的 Job 執行 4 Schedule Schedule 5 6// The next time the job will run. This is the zero time if Cron has not been 7// started or this entry's schedule is unsatisfiable 8// Job 下一次執行的時間 9 Next time.Time1011// The last time this job was run. This is the zero time if the job has never12// been run.13// 上一次執行時間14 Prev time.Time1516// The Job to run.17// 要執行的 Job18 Job Job19}
Job:每一個實體包含一個需要運行的Job這是一個接口,只有一個方法:Run1type Job interface {2 Run()3}
由於 Entity 中需要 Job 類型,因此,我們希望定期運行的任務,就需要實現 Job 接口。同時,由於 Job 接口只有一個無參數無返回值的方法,為了使用方便,作者提供了一個類型:
type FuncJob func()
它通過簡單的實現 Run() 方法來實現 Job 接口:
func (f FuncJob) Run() { f() }
這樣,任何無參數無返回值的函數,通過強制類型轉換為 FuncJob,就可以當作 Job 來使用了,AddFunc 方法 就是這麼做的。
Schedule:每個實體包含一個調度器(Schedule)負責調度 Job 的執行。它也是一個接口。
1type Schedule interface {2 // Return the next activation time, later than the given time.3 // Next is invoked initially, andthen each time the job is run.4 // 返回同一 Entity 中的 Job 下一次執行的時間5 Next(time.Time) time.Time6}
Schedule 的具體實現通過解析 Cron 表達式得到。
庫中提供了 Schedule 的兩個具體實現,分別是 SpecSchedule 和 ConstantDelaySchedule。
① SpecSchedule
1type SpecSchedule struct {2Second, Minute, Hour, Dom, Month, Dow uint643}
從開始介紹的 Cron 表達式可以容易得知各個欄位的意思,同時,對各種表達式的解析也會最終得到一個 SpecSchedule 的實例。庫中的 Parse 返回的其實就是 SpecSchedule 的實例(當然也就實現了 Schedule 接口)。
② ConstantDelaySchedule
1type ConstantDelaySchedule struct {2 Delay time.Duration // 循環的時間間隔3}
這是一個簡單的循環調度器,如:每 5 分鐘。注意,最小單位是秒,不能比秒還小,比如 毫秒。
通過 Every 函數可以獲取該類型的實例,如:
1constDelaySchedule := Every(5e9)
得到的是一個每 5 秒執行一次的調度器。
函數調用
函數① 實例化 Cron1funcNew() *Cron {2return &Cron{3 entries: nil,4 add: make(chan *Entry),5 stop: make(chanstruct{}),6 snapshot: make(chan []*Entry),7 running: false,8 }9}
可見實例化時,成員使用的基本是默認值;
② 解析 Cron 表達式
1funcParse(spec string)(_ Schedule, err error)
spec 可以是:
Full crontab specs, e.g. 「* * * * * ?」Descriptors, e.g. 「@midnight」, 「@every 1h30m」
② 成員方法
1// 將 job 加入 Cron 中 2// 如上所述,該方法只是簡單的通過 FuncJob 類型強制轉換 cmd,然後調用 AddJob 方法 3func(c *Cron)AddFunc(spec string, cmd func()) error 4 5// 將 job 加入 Cron 中 6// 通過 Parse 函數解析 cron 表達式 spec 的到調度器實例(Schedule),之後調用 c.Schedule 方法 7func(c *Cron)AddJob(spec string, cmd Job)error 8 9// 獲取當前 Cron 總所有 Entities 的快照10func(c *Cron)Entries() []*Entry1112// 通過兩個參數實例化一個 Entity,然後加入當前 Cron 中13// 注意:如果當前 Cron 未運行,則直接將該 entity 加入 Cron 中;14// 否則,通過 add 這個成員 channel 將 entity 加入正在運行的 Cron 中15func(c *Cron)Schedule(schedule Schedule, cmd Job)1617// 新啟動一個 goroutine 運行當前 Cron18func(c *Cron)Start()1920// 通過給 stop 成員發送一個 struct{}{} 來停止當前 Cron,同時將 running 置為 false21// 從這裡知道,stop 只是通知 Cron 停止,因此往 channel 發一個值即可,而不關心值是多少22// 所以,成員 stop 定義為空 struct23func(c *Cron)Stop()24
如果對每個方法調用還是不了解可以去看一下每隔函數的實現源碼
example
1package main 2 3import ( 4"log" 5 6"github.com/robfig/cron" 7) 8 9type Hello struct {10 Str string11}1213func(h Hello)Run() {14 log.Println(h.Str)15}1617funcmain() {18 log.Println("Starting...")1920 c := cron.New()21 h := Hello{"I Love You!"}22// 添加定時任務23 c.AddJob("*/2 * * * * * ", h)24// 添加定時任務25 c.AddFunc("*/5 * * * * * ", func() {26 log.Println("hello word")27 })2829 s, err := cron.Parse("*/3 * * * * *")30if err != nil {31 log.Println("Parse error")32 }33 h2 := Hello{"I Hate You!"}34 c.Schedule(s, h2)35// 其中任務36 c.Start()37// 關閉任務38defer c.Stop()39select {40 }41}
參考GO語言版CRONTAB官方文檔
版權申明:內容來源網絡,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝。
Golang語言社區
ID:Golangweb
www.GolangWeb.com
遊戲伺服器架構丨分布式技術丨大數據丨遊戲算法學習