golang cron 定時任務

2021-01-08 Golang語言社區

作者:_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

遊戲伺服器架構丨分布式技術丨大數據丨遊戲算法學習

相關焦點

  • golang定時任務實現gorm操作資料庫部署配置及注意事項
    golang作為一個工程性很強的語言,本示例將示例一個golang定時任務從開發到部署的整個過程。一.首先,創建項目結構golang定時任務項目結構本示例定時任務主要使用 github.com/robfig/cron本示例啟動了三個定時任務1.是每天早上8點2.是每隔5分鐘執行一次3.是每隔15分鐘執行一次
  • Golang 定時任務管理
    需求在開發中,經常遇到一些需要定時任務的場景。各個語言都有定時語言的庫,Golang Cron 提供了Crontab Golang語言版本。這個庫非常不錯,提供最基本的定時任務編排的功能。但是一些複雜需求無法滿足,比如任何定時任務都有可能失敗,失敗了就panic了,這樣非常不友好。
  • Go 每日一庫之定時任務庫:cron
    對象使用時,首先通過cron.New()創建cron對象,通過該對象管理定時任務。通過調用cron的AddFunc()方法添加定時任務。AddFun()入參為二,參數一是以字符串的形式指定觸發任務規則,參數二是無入參的函數,任務觸發時執行函數。
  • Go 每日一庫之 cron
    簡介cron一個用於管理定時任務的庫,用 Go 實現 Linux 中crontab這個命令的效果。之前我們也介紹過一個類似的 Go 庫——gron。gron代碼小巧,用於學習是比較好的。但是它功能相對簡單些,並且已經不維護了。如果有定時任務需求,還是建議使用cron。
  • Linux下如何創建定時任務?
    前言在linux裡面,作為運維人員,會時不時地用到定時任務,定時任務的管理是由cron來管理的。例如:mysql的定時備份。mysql的定時備份實現思路是這樣的:創建一個用於執行mysql的shell腳本,創建一個定時任務,定時任務指向該shell腳本,啟動定時任務計劃,定時執行。linux下的定時任務1.安裝cron通過命令「systemctl start cron」發現未找到cron.service。
  • 13-SpringBoot項目使用定時任務
    ScheduledExecutorService:也jdk自帶的一個類;是基於線程池設計的定時任務類,每個調度任務都會分配到線程池中的一個線程去執行,也就是說,任務是並發執行,互不影響。Spring Task:Spring3.0以後自帶的task,可以將它看成一個輕量級的Quartz,而且使用起來比Quartz簡單許多。
  • springboot中定時任務執行Quartz的使用
    環境:springboot2.2.11.RELEASE2種方式執行定時任務1、通過springboot的方式2、使用Quartz實現定時任務方式一:通過springboot的定時任務1、開啟定時任務功能@EnableScheduling
  • SpringBoot定時任務:schedule、quartz
    所以需要使用Scheduled定時任務機制時,需要在工程中依賴對應資源,具體如下:如果在spring應用中需要啟用Scheduled定時任務,則需要在啟動類上增加註解@EnableScheduling,代表啟用Scheduled定時任務機制。
  • PHP在Linux下執行定時任務的實現思路詳解
    接下來就是設置定時任務來運行cron.bat。依次打開:「開始–>控制面板–>任務計劃–>添加任務計劃」,在打開的界面中設置定時任務的時間、密碼,通過選擇,把cron.bat掛載進去。
  • SpringBoot定時任務EnableScheduling
    寫一個SpringBoot的啟動類啟動類裡面使用@EnableScheduling 註解開啟定時任務功能。編寫定時任務要在任務的類上寫@Component,將當前的任務類注入到容器。要在任務方法上寫@Scheduled,然後編寫cron表達式。
  • django定時任務庫 django_apscheduler
    django_apscheduler 在做定時任務的時候這個庫挺有用的,記得在這個庫還不存在的時候,自己也寫了一個和這個庫功能差不多的django模塊。也能用,不過不是很穩定,每次重啟wsgi的時候,都要手動啟動任務。無意中發現了django_apscheduler 這塊第三方庫,用了下挺好用的。
  • 全面解決Linux定時任務不能正常運行的三種方法
    ssh登錄運行shell命令的終端窗口一,檢查服務狀態開啟服務 1.1 service crond/cron status1.2 service crond/cron start1.3 service crond/cron stopcrond 是centos命令名,cron是ubuntu命令名。
  • Go實現cron計劃任務
    簡介在跑任務程序的時候,我們希望在某個時間點執行某些操作,這時候就可以使用cron快速實現。Go實現在Go開源項目中有好幾個都有實現cron的功能,例如:github.com/robfig/cron這個項目下有支持秒級別的cron任務,最新版本反而不支持,需要注意,目前最新版本是v3,如果不指定版本號,默認是使用v1的版本
  • Linux技巧:介紹設置定時周期執行任務的方法
    這些定時任務由 cron 守護進程來執行,該進程一直運行在後臺,會定時檢查 crontab 文件來判斷需要做什麼,如果某個任務需要被執行,就會執行該任務指定的操作。一般來說,系統啟動時,init 進程會啟動 cron 進程。可以使用 man crontab 來查看 crontab 命令的幫助信息。
  • Linux基礎命令介紹十四:定時任務
    編輯時系統會選定默認編輯器,在筆者的環境中是vi 通過直接編輯文件/etc/crontab可以設置系統級別的cron table。 使用crontab -e的方式編輯時,會在/tmp下面生成一個臨時文件,保存後crond會將內容寫入到/var/spool/cron下面一個和用戶名同名的文件中,crond會在保存時做語法檢查。這也是推薦的設置定時任務的用法。
  • 定時任務調度框架Quartz
    最近需要寫一個每天定點自動執行的定時任務,對於以前自己寫小項目,可能會選擇java自帶的Timer類,但是對於公司中的項目,Timer類實現定時任務只能有一個後臺線程執行任務,並且只能讓程序按照某個頻度執行,並不能在指定時間點執行。
  • Spring Boot實現定時任務新解,你是否能get到?
    在日常的開發過程中經常使用到定時任務,在springMVC的開發中,經常和quartz框架進行集成使用,但在springboot中沒有這麼做,而是使用了java的線程池來實現定時任務。一、概述在springboot中使用定時任務非常簡單,只需要簡單的幾步即可完成。
  • springboot之動態修改cron表達式
    前言在實際項目開發中,使用quratz石英鐘定時任務是經常使用到的,定時任務可以根據指定的時間周期性的完成一個任務。我們通常使用的是@Scheduled註解來完成設置定時任務,但是有時候我們往往需要對周期性的時間的設置會做一些改變,那麼這個時候使用此註解就不太方便了,原因在於這個註解中配置的cron表達式必須是常量,那麼當我們修改定時參數的時候,就需要停止服務,重新部署。說明 修改cron定時參數後,不需要重啟伺服器就可以動態修改。
  • linux 任務 啟動 定時 - CSDN
    os主要有單用戶單任務、單用戶多任務、多用戶多任務幾種類型。在多用戶多任務作業系統中,對每個用戶運行環境的設置就十分重要。一、開機自啟動任務。我們首先要明確開機自啟動是個什麼概念。開機自啟動的任務主要在兩個時間點發生,一個是用戶沒有登陸之前,系統正在啟動的過程中,另一個是用戶成功登陸之後(即通過登陸界面輸入用戶名密碼登陸之後)。
  • 一個高效的定時任務系統
    開箱即用的定時器單機版定時器①cron/crontabcron 是 Linux 中的一個定時任務機制。cron 表示一個在後臺運行的守護進程,crontab 是一個設置 cron 的工具,所有的定時任務都寫在 crontab 文件中。cron 調度的是 /etc/crontab 文件中的內容。crontab 的命令構成為時間+動作,其時間有分、時、日、月、周五種。這裡要注意,最小單位為分鐘,默認是不到秒的級別,大家也給出了各種精確到秒的方案,有興趣的可以搜索一下。