欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言定時任務(wù)的實現(xiàn)示例

 更新時間:2023年05月31日 10:31:42   作者:zsx_yiyiyi  
本文主要介紹了Go語言定時任務(wù)的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

robfig/cron 是Go語言實現(xiàn)的開源定時任務(wù)調(diào)度框架,核心代碼是巧妙的使用chan + select + for實現(xiàn)了一個輕量

級調(diào)度協(xié)程,不但語法簡潔,而且具有很好的性能。

Cron是Go中用于設(shè)置定時任務(wù)的一個庫,需要注意的是,Cron庫分兩個大版本,v1.2和v3.0,其功能和go get地

址都是不同的,注意區(qū)分。

v1.2官方文檔:https://pkg.go.dev/github.com/robfig/cron

v3官方文檔:https://pkg.go.dev/github.com/robfig/cron/v3

cron github倉庫:https://github.com/robfig/cron

1、安裝依賴

# v1.2
go get github.com/robfig/cron
# v3
go get github.com/robfig/cron/v3@v3.0.0

2、定時任務(wù)簡單案例

package main
import (
?? ?"fmt"
?? ?"github.com/robfig/cron/v3"
?? ?"time"
)
func main() {
?? ?// 新建一個定時任務(wù)對象,根據(jù)cron表達式進行時間調(diào)度,cron可以精確到秒,大部分表達式格式也是從秒開始
?? ?// 默認從分開始進行時間調(diào)度
?? ?// cronTab := cron.New()
?? ?// 精確到秒
?? ?cronTab := cron.New(cron.WithSeconds())
?? ?// 定義定時器調(diào)用的任務(wù)函數(shù)
?? ?task := func() {
?? ??? ?fmt.Println("hello world", time.Now())
?? ?}
?? ?// 定時任務(wù),cron表達式,每五秒一次
?? ?spec := "*/5 * * * * ?"
?? ?// 添加定時任務(wù)
?? ?cronTab.AddFunc(spec, task)
?? ?// 啟動定時器
?? ?cronTab.Start()
?? ?// 阻塞主線程停止
?? ?select {}
}

# 輸出信息
hello world 2023-05-30 12:48:40.0089132 +0800 CST m=+0.087419701
hello world 2023-05-30 12:48:45.0040694 +0800 CST m=+5.082575901
hello world 2023-05-30 12:48:50.001667 +0800 CST m=+10.080173501
hello world 2023-05-30 12:48:55.0013075 +0800 CST m=+15.079814001
hello world 2023-05-30 12:49:00.0011284 +0800 CST m=+20.079634901
hello world 2023-05-30 12:49:05.0080655 +0800 CST m=+25.086572001
......

3、Cron表達式

cron 表達式是一個好東西,這個東西不僅 Java 的 quartZ 能用到,Go 語言中也可以用到。

Linux 也是可以用 crontab -e 命令來配置定時任務(wù)。

Go 語言和 Java 中都是可以精確到秒的,但是 Linux 中不行。

cron表達式代表一個時間的集合,使用6個空格分隔的字段表示:

字段名是否必須允許的值允許的特定字符
秒(Seconds)0-59* / , -
分(Minute)0-59* / , -
時(Hours)0-23* / , -
日(Day of month)1-31* / , - ?
月(Month)1-12 或 JAN-DEC* / , -
星期(Day of week)0-6 或 SUM-SAT* / , - ?

特殊字符說明:

? 只能在 day 和 week 中使用,標識未說明的值,用以解決 day 和 week 的沖突,比如 * * * 10 * ? 表示每

月10號觸發(fā),而換成 * 則表示不管星期幾都可觸發(fā),與前者發(fā)生沖突。

3.1 Cron表達式說明

  • 月(Month)和星期(Day of week)字段的值不區(qū)分大小寫,如:SUN、Sun 和 sun 是一樣的。
  • 星期(Day of week)字段如果沒提供,相當于是 *

3.2 Cron表達式示例說明

如果我們使用 crontab := cron.New(cron.WithSeconds()),我們的定時任務(wù)表達式需要為:

* * * * * *

如果我們使用 cronTab := cron.New(),我們的定時任務(wù)表達式需要為:

* * * * *,不包含秒

這 6 個 * 分別代表什么意思呢?

# 第一個*: second,范圍(0 - 60)
# 第二個*: min,范圍(0 - 59)
# 第三個*: hour,范圍(0 - 23)
# 第四個*: day of month,范圍(1 - 31)
# 第五個*: month,范圍(1 - 12)
# 第六個*: day of week,范圍(0 - 6) (0 to 6 are Sunday to Saturday)
* * * * * *

3.3 cron特定字符說明

符號說明
(*)表示 cron 表達式能匹配該字段的所有值。如在第5個字段使用星號(month),表示每個月
(/)表示增長間隔,如第1個字段(minutes) 值是 3-59/15,表示每小時的第3分鐘開始執(zhí)行一次,之后每隔 15 分鐘執(zhí)行一次(即 3、18、33、48 這些時間點執(zhí)行),這里也可以表示為:3/15
(,)用于枚舉值,如第6個字段值是 MON,WED,FRI,表示 星期一、三、五 執(zhí)行
(-)表示一個范圍,如第3個字段的值為 9-17 表示 9am 到 5pm 直接每個小時(包括9和17)
(?)只用于 日(Day of month) 和 星期(Day of week),表示不指定值,可以用于代替 *

3.4 常用cron舉例

每隔5秒執(zhí)行一次:*/5 * * * * ?
每隔1分鐘執(zhí)行一次:0 */1 * * * ?
每天23點執(zhí)行一次:0 0 23 * * ?
每天凌晨1點執(zhí)行一次:0 0 1 * * ?
每月1號凌晨1點執(zhí)行一次:0 0 1 1 * ?
每周一和周三晚上22:30: 00 30 22 * * 1,3 
在26分、29分、33分執(zhí)行一次:0 26,29,33 * * * ?
每天的0點、13點、18點、21點都執(zhí)行一次:0 0 0,13,18,21 * * ?
每年三月的星期四的下午14:10和14:40:  00 10,40 14 ? 3 4 

3.5 預(yù)定義的時間格式

您可以使用幾個預(yù)定義的表達式來代替上表的表達式,使用如下:

輸入描述等式
@yearly (or @annually)每年一次,1月1日午夜0 0 0 1 1 *
@monthly每月運行一次,每月第一天午夜0 0 0 1 * *
@weekly每周運行一次,周六/周日之間的午夜0 0 0 * * 0
@daily (or @midnight)每天午夜運行一次0 0 0 * * *
@hourly每小時運行一次0 0 * * * *

還可以安排作業(yè)以固定的間隔執(zhí)行,從添加作業(yè)或運行cron時開始。這是通過如下格式化cron規(guī)范來支持的:

@every <duration>
// 例如
c := cron.New() 
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })

4、時區(qū)

默認情況下,所有時間都是基于當前時區(qū)的,也可自定義:在時間字符串前面添加一個CRON_TZ= + 具體時區(qū)

一些常用的時區(qū):

  • 東京時區(qū):Asia/Tokyo
  • 紐約時區(qū):America/New_York
  • 上海時區(qū):Asia/Shanghai
  • 香港時區(qū):Asia/Hong_Kong

創(chuàng)建cron對象時增加一個時區(qū)選項cron.WithLocation(location),location為time.LoadLocation(zone)加載的時區(qū)

對象,zone為具體的時區(qū)格式。

package main
import (
?? ?"fmt"
?? ?"github.com/robfig/cron/v3"
?? ?"time"
)
func main() {
?? ?//直接配置時區(qū)
?? ?nyc, _ := time.LoadLocation("America/New_York")
?? ?// cron.New(cron.WithLocation(time.UTC))
?? ?c := cron.New(cron.WithLocation(nyc),cron.WithSeconds())
?? ?c.AddFunc("*/5 * * * * ?", func() {
?? ??? ?fmt.Println("Every 5 second at New York")
?? ?})
?? ?// 參數(shù)里面配置時區(qū)
?? ?c.AddFunc("CRON_TZ=Asia/Tokyo */5 * * * * ?", func() {
?? ??? ?fmt.Println("Every 5 second at Tokyo")
?? ?})
?? ?c.Start()
?? ?select {}
}

# 輸出
Every 5 second at New York
Every 5 second at Tokyo
Every 5 second at Tokyo
Every 5 second at New York
......

5、自定義定時任務(wù)以及多個定時任務(wù)

自定義定時任務(wù)只需要實現(xiàn)Job接口的Run方法。

package main
import (
?? ?"fmt"
?? ?"github.com/robfig/cron/v3"
?? ?"time"
)
type Task1 struct {
?? ?Name string
}
// 自定義定時任務(wù)只需要實現(xiàn)Job接口的Run方法
func (t *Task1) Run() {
?? ?fmt.Println("Task1: ", t.Name)
}
type Task2 struct {
?? ?Name string
}
// 自定義定時任務(wù)只需要實現(xiàn)Job接口的Run方法
func (t *Task2) Run() {
?? ?fmt.Println("Task2: ", t.Name)
}
func main() {
?? ?cronTab := cron.New(cron.WithSeconds())
?? ?// 定義定時器調(diào)用的任務(wù)函數(shù)
?? ?// 定時任務(wù)
?? ?// cron表達式,每五秒一次
?? ?spec := "*/5 * * * * ?"
?? ?//定義定時器調(diào)用的任務(wù)函數(shù)
?? ?task := func() {
?? ??? ?fmt.Println("hello world", time.Now())
?? ?}
?? ?// 添加多個定時器
?? ?cronTab.AddFunc(spec, task)
?? ?cronTab.AddJob(spec, &Task1{Name: "tom"})
?? ?cronTab.AddJob(spec, &Task2{Name: "merry"})
?? ?// 啟動定時器
?? ?cronTab.Start()
?? ?// 關(guān)閉,但是不能關(guān)閉已經(jīng)在執(zhí)行中的任務(wù)
?? ?defer cronTab.Stop()
?? ?// 阻塞主線程停止
?? ?select {}
}

# 輸出
Task1:  tom
Task2:  merry
hello world 2023-05-30 15:03:55.006422 +0800 CST m=+1.424751701
Task2:  merry
Task1:  tom
hello world 2023-05-30 15:04:00.0057737 +0800 CST m=+6.424103401
Task2:  merry
Task1:  tom
hello world 2023-05-30 15:04:05.0003003 +0800 CST m=+11.418630001
......

6、主要類型或接口說明

6.1 Job

任務(wù)抽象(業(yè)務(wù)隔離):任務(wù)抽象成一個 Job 接口,業(yè)務(wù)邏輯類只需實現(xiàn)該接口。

每一個實體包含一個需要運行的 Job,這是一個接口,只有一個方法:Run。

// Job is an interface for submitted cron jobs.
type Job interface {
    Run()
}

由于 Entity 中需要 Job 類型,因此,我們希望定期運行的任務(wù),就需要實現(xiàn) Job 接口。同時,由于 Job 接口只有一個無參數(shù)無返回值的方法,為了使用方便,作者提供了一個類型

// 它通過簡單的實現(xiàn)Run()方法來實現(xiàn)Job接口
type FuncJob func()
// 這樣,任何無參數(shù)無返回值的函數(shù),通過強制類型轉(zhuǎn)換為FuncJob,就可以當作Job來使用了,AddFunc方法就是這么做的
func (f FuncJob) Run() { f() }

6.2 Schedule

計劃接口:通過當前時間計算任務(wù)的下次執(zhí)行執(zhí)行時間,具體實現(xiàn)類可以根據(jù)實際需求實現(xiàn)。

每個實體包含一個調(diào)度器(Schedule)負責(zé)調(diào)度 Job 的執(zhí)行。它也是一個接口,Schedule 的具體實現(xiàn)通過解析 Cron

表達式得到。庫中提供了 Schedule 的兩個具體實現(xiàn),分別是 SpecSchedule 和 ConstantDelaySchedule。

// Schedule describes a job's duty cycle.
type Schedule interface {
    // Next returns the next activation time, later than the given time.
    // Next is invoked initially, and then each time the job is run.
    // 返回同一Entity中的Job下一次執(zhí)行的時間
    Next(time.Time) time.Time
}

6.2.1 SpecSchedule

從開始介紹的 Cron 表達式可以容易得知各個字段的意思,同時,對各種表達式的解析也會最終得到一個

SpecSchedule 的實例。庫中的 Parse 返回的其實就是 SpecSchedule 的實例(當然也就實現(xiàn)了 Schedule 接口)。

// SpecSchedule specifies a duty cycle (to the second granularity), based on a
// traditional crontab specification. It is computed initially and stored as bit sets.
type SpecSchedule struct {
?? ?Second, Minute, Hour, Dom, Month, Dow uint64
?? ?// Override location for this schedule.
?? ?Location *time.Location
}

該類的 Next 方法實現(xiàn)比較多,這里就不介紹了。

6.2.2 ConstantDelaySchedule

// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes".
// It does not support jobs more frequent than once a second.
type ConstantDelaySchedule struct {
    // 循環(huán)的時間間隔
    Delay time.Duration
}

這是一個簡單的循環(huán)調(diào)度器,如:每 5 分鐘。注意,最小單位是秒,不能比秒還小,比如毫秒。

實現(xiàn):

// Next returns the next time this should be run.
// This rounds so that the next activation time will be on the second.
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {
    return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond)
}

通過 Every 函數(shù)可以獲取該類型的實例,如下得到的是一個每 5 秒執(zhí)行一次的調(diào)度器。

package main
import (
?? ?"fmt"
?? ?"github.com/robfig/cron/v3"
)
func main() {
?? ?constDelaySchedule1 := cron.Every(5e9)
?? ?// 5s
?? ?fmt.Println(constDelaySchedule1.Delay)
?? ?constDelaySchedule2 := cron.Every(5e6)
?? ?// 1s
?? ?fmt.Println(constDelaySchedule2.Delay)
}

Every 的實現(xiàn):

// Every returns a crontab Schedule that activates once every duration.
// Delays of less than a second are not supported (will round up to 1 second).
// Any fields less than a Second are truncated.
func Every(duration time.Duration) ConstantDelaySchedule {
    if duration < time.Second {
        duration = time.Second
    }
    return ConstantDelaySchedule{
        Delay: duration - time.Duration(duration.Nanoseconds())%time.Second,
    }
}

6.3 Entry

定時任務(wù)對象:保存執(zhí)行的任務(wù)Job、計算執(zhí)行時間。

// Entry consists of a schedule and the func to execute on that schedule.
type Entry struct {
?? ?// ID is the cron-assigned ID of this entry, which may be used to look up a
?? ?// snapshot or remove it.
?? ?ID EntryID
?? ?// Schedule on which this job should be run.
? ?? ?// 負責(zé)調(diào)度當前Entity中的Job執(zhí)行
?? ?Schedule Schedule
?? ?// Next time the job will run, or the zero time if Cron has not been
?? ?// started or this entry's schedule is unsatisfiable
? ?? ?// Job下一次執(zhí)行的時間
?? ?Next time.Time
?? ?// Prev is the last time this job was run, or the zero time if never.
? ?? ?// 上一次執(zhí)行時間
?? ?Prev time.Time
?? ?// WrappedJob is the thing to run when the Schedule is activated.
?? ?WrappedJob Job
?? ?// Job is the thing that was submitted to cron.
?? ?// It is kept around so that user code that needs to get at the job later,
?? ?// e.g. via Entries() can do so.
? ?? ?// 要執(zhí)行的Job
?? ?Job Job
}

6.4 Cron

任務(wù)調(diào)度管理:保存定時任務(wù)對象(Entry),調(diào)度任務(wù)執(zhí)行,提供新增、刪除接口(涉及關(guān)聯(lián)資源競爭)和暫停。

注意:

  • Cron 結(jié)構(gòu)沒有導(dǎo)出任何成員。
  • 有一個成員stop,類型是struct{},即空結(jié)構(gòu)體。
// Cron keeps track of any number of entries, invoking the associated func as
// specified by the schedule. It may be started, stopped, and the entries may
// be inspected while running.
type Cron struct {
    entries   []*Entry
    chain     Chain
    stop      chan struct{} // 控制Cron實例暫停
    add       chan *Entry    // 當Cron已經(jīng)運行了,增加新的Entity是通過add這個channel實現(xiàn)的
    remove    chan EntryID
    snapshot  chan chan []Entry // 獲取當前所有entity的快照
    running   bool // 當已經(jīng)運行時為true,否則為false
    logger    Logger
    runningMu sync.Mutex
    location  *time.Location
    parser    Parser
    nextID    EntryID
    jobWaiter sync.WaitGroup
}
// Remove an entry from being run in the future.
func (c *Cron) Remove(id EntryID) {
?? ?c.runningMu.Lock()
?? ?defer c.runningMu.Unlock()
?? ?if c.running {
?? ??? ?c.remove <- id
?? ?} else {
?? ??? ?c.removeEntry(id)
?? ?}
}
// Schedule adds a Job to the Cron to be run on the given schedule.
// The job is wrapped with the configured Chain.
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
?? ?c.runningMu.Lock()
?? ?defer c.runningMu.Unlock()
?? ?c.nextID++
?? ?entry := &Entry{
?? ??? ?ID: ? ? ? ? c.nextID,
?? ??? ?Schedule: ? schedule,
?? ??? ?WrappedJob: c.chain.Then(cmd),
?? ??? ?Job: ? ? ? ?cmd,
?? ?}
?? ?if !c.running {
?? ??? ?c.entries = append(c.entries, entry)
?? ?} else {
?? ??? ?c.add <- entry
?? ?}
?? ?return entry.ID
}

7、實例化主要方法說明

7.1 實例化

啟動時會開啟唯一協(xié)程執(zhí)行run方法,計算任務(wù)執(zhí)行時間,執(zhí)行,任務(wù)管理等:

// New returns a new Cron job runner, modified by the given options.
//
// Available Settings
//
// ? Time Zone
// ? ? Description: The time zone in which schedules are interpreted
// ? ? Default: ? ? time.Local
//
// ? Parser
// ? ? Description: Parser converts cron spec strings into cron.Schedules.
// ? ? Default: ? ? Accepts this spec: https://en.wikipedia.org/wiki/Cron
//
// ? Chain
// ? ? Description: Wrap submitted jobs to customize behavior.
// ? ? Default: ? ? A chain that recovers panics and logs them to stderr.
//
// See "cron.With*" to modify the default behavior.
// 實例化時,成員使用的基本是默認值
func New(opts ...Option) *Cron {
?? ?c := &Cron{
?? ??? ?entries: ? nil,
?? ??? ?chain: ? ? NewChain(),
?? ??? ?add: ? ? ? make(chan *Entry),
?? ??? ?stop: ? ? ?make(chan struct{}),
?? ??? ?snapshot: ?make(chan chan []Entry),
?? ??? ?remove: ? ?make(chan EntryID),
?? ??? ?running: ? false,
?? ??? ?runningMu: sync.Mutex{},
?? ??? ?logger: ? ?DefaultLogger,
?? ??? ?location: ?time.Local,
?? ??? ?parser: ? ?standardParser,
?? ?}
?? ?for _, opt := range opts {
?? ??? ?opt(c)
?? ?}
?? ?return c
}
// Start the cron scheduler in its own goroutine, or no-op if already started.
func (c *Cron) Start() {
?? ?c.runningMu.Lock()
?? ?defer c.runningMu.Unlock()
?? ?if c.running {
?? ??? ?return
?? ?}
?? ?c.running = true
?? ?go c.run()
}

7.2 主要方法

核心調(diào)度:計算下次執(zhí)行時間 -> 排序 -> 取最早執(zhí)行數(shù)據(jù) -> timer 等待,因為只有一個協(xié)程在執(zhí)行這個run的調(diào)

度,所以不存在資源競爭,不需要加鎖,另外考慮到執(zhí)行任務(wù)可能涉及阻塞,例如:IO操作,所以一般startJob方

法會開啟協(xié)程執(zhí)行。

// Run the cron scheduler, or no-op if already running.
func (c *Cron) Run() {
?? ?c.runningMu.Lock()
?? ?if c.running {
?? ??? ?c.runningMu.Unlock()
?? ??? ?return
?? ?}
?? ?c.running = true
?? ?c.runningMu.Unlock()
?? ?c.run()
}
// run the scheduler.. this is private just due to the need to synchronize
// access to the 'running' state variable.
func (c *Cron) run() {
?? ?c.logger.Info("start")
?? ?// Figure out the next activation times for each entry.
?? ?now := c.now()
?? ?for _, entry := range c.entries {
?? ??? ?entry.Next = entry.Schedule.Next(now)
?? ??? ?c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next)
?? ?}
?? ?for {
?? ??? ?// Determine the next entry to run.
?? ??? ?sort.Sort(byTime(c.entries))
?? ??? ?var timer *time.Timer
?? ??? ?if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
?? ??? ??? ?// If there are no entries yet, just sleep - it still handles new entries
?? ??? ??? ?// and stop requests.
?? ??? ??? ?timer = time.NewTimer(100000 * time.Hour)
?? ??? ?} else {
?? ??? ??? ?timer = time.NewTimer(c.entries[0].Next.Sub(now))
?? ??? ?}
?? ??? ?for {
?? ??? ??? ?select {
?? ??? ??? ?case now = <-timer.C:
?? ??? ??? ??? ?now = now.In(c.location)
?? ??? ??? ??? ?c.logger.Info("wake", "now", now)
?? ??? ??? ??? ?// Run every entry whose next time was less than now
?? ??? ??? ??? ?for _, e := range c.entries {
?? ??? ??? ??? ??? ?if e.Next.After(now) || e.Next.IsZero() {
?? ??? ??? ??? ??? ??? ?break
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?c.startJob(e.WrappedJob)
?? ??? ??? ??? ??? ?e.Prev = e.Next
?? ??? ??? ??? ??? ?e.Next = e.Schedule.Next(now)
?? ??? ??? ??? ??? ?c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next)
?? ??? ??? ??? ?}
?? ??? ??? ?case newEntry := <-c.add:
?? ??? ??? ??? ?timer.Stop()
?? ??? ??? ??? ?now = c.now()
?? ??? ??? ??? ?newEntry.Next = newEntry.Schedule.Next(now)
?? ??? ??? ??? ?c.entries = append(c.entries, newEntry)
?? ??? ??? ??? ?c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next)
?? ??? ??? ?case replyChan := <-c.snapshot:
?? ??? ??? ??? ?replyChan <- c.entrySnapshot()
?? ??? ??? ??? ?continue
?? ??? ??? ?case <-c.stop:
?? ??? ??? ??? ?timer.Stop()
?? ??? ??? ??? ?c.logger.Info("stop")
?? ??? ??? ??? ?return
?? ??? ??? ?case id := <-c.remove:
?? ??? ??? ??? ?timer.Stop()
?? ??? ??? ??? ?now = c.now()
?? ??? ??? ??? ?c.removeEntry(id)
?? ??? ??? ??? ?c.logger.Info("removed", "entry", id)
?? ??? ??? ?}
?? ??? ??? ?break
?? ??? ?}
?? ?}
}
// startJob runs the given job in a new goroutine.
func (c *Cron) startJob(j Job) {
?? ?c.jobWaiter.Add(1)
?? ?go func() {
?? ??? ?defer c.jobWaiter.Done()
?? ??? ?j.Run()
?? ?}()
}

7.3 其它成員方法

// EntryID標識Cron實例中的entry
type EntryID int
// 將job加入Cron中
// 如上所述,該方法只是簡單的通過FuncJob類型強制轉(zhuǎn)換cmd,然后調(diào)用AddJob方法
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error)?
// 將job加入Cron中
// 通過Parse函數(shù)解析cron表達式spec的到調(diào)度器實例(Schedule),之后調(diào)用c.Schedule方法
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error)
// 獲取當前Cron總所有Entities的快照
func (c *Cron) Entries() []*Entry
// Location獲取時區(qū)位置
func (c *Cron) Location() *time.Location?
// Entry返回給定項的快照,如果找不到則返回nil
func (c *Cron) Entry(id EntryID) Entry
// 刪除將來運行的條目
func (c *Cron) Remove(id EntryID)?
// 通過兩個參數(shù)實例化一個Entity,然后加入當前Cron中
// 注意: 如果當前Cron未運行,則直接將該entity加入Cron中
// 否則,通過add這個成員channel將entity加入正在運行的Cron中
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID
// 新啟動一個goroutine運行當前Cron
func (c *Cron) Start()
// 通過給stop成員發(fā)送一個struct{}{}來停止當前Cron,同時將running置為false
// 從這里知道,stop只是通知Cron停止,因此往channel發(fā)一個值即可,而不關(guān)心值是多少
// 所以,成員stop定義為空struct
func (c *Cron) Stop()
// 運行cron調(diào)度程序,如果已經(jīng)在運行,則不運行op
func (c *Cron) Run()

8、其它定時任務(wù)的實現(xiàn)

8.1 最簡單的定時任務(wù)

使用協(xié)程和 Sleep方式:

package main
import (
?? ?"fmt"
?? ?"time"
)
func main(){
?? ?go func() {
?? ??? ?for true {
?? ??? ??? ?fmt.Println("Hello World!",time.Now())
?? ??? ??? ?time.Sleep(1 * time.Second)
?? ??? ?}
?? ?}()
?? ?select {
?? ?}
}

# 輸出
Hello World! 2023-05-30 22:26:12.454977 +0800 CST m=+7.021813601
Hello World! 2023-05-30 22:26:13.4553086 +0800 CST m=+8.022145201
Hello World! 2023-05-30 22:26:14.4555344 +0800 CST m=+9.022371001
Hello World! 2023-05-30 22:26:15.4566625 +0800 CST m=+10.023499101
Hello World! 2023-05-30 22:26:16.4570511 +0800 CST m=+11.023887701
Hello World! 2023-05-30 22:26:17.4579146 +0800 CST m=+12.024751201
Hello World! 2023-05-30 22:26:18.4589781 +0800 CST m=+13.025814701
......

8.2 Timer實現(xiàn)定時任務(wù)

除了使用 cron 庫可以實現(xiàn)定時任務(wù),使用 time 庫也可以實現(xiàn)定時任務(wù)。

在Go語言中,可以使用 time 包提供的 Timer 和 Ticker 類型設(shè)置定時任務(wù)。Timer 用于在未來的某個時間點執(zhí)行

一次任務(wù),而 Ticker 則用于每隔一定時間執(zhí)行一次任務(wù)。

8.2.1 Timer啟動定時器

Timer 實現(xiàn)定時器,延遲執(zhí)行,這個定時器只會觸發(fā)一次。

下面是一個使用 Timer 設(shè)置定時任務(wù)的例子:

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?// 創(chuàng)建一個Timer實例,設(shè)置2秒后執(zhí)行任務(wù)
?? ?t := time.NewTimer(2 * time.Second)
?? ?// 記得釋放Timer資源
?? ?defer t.Stop()
?? ?// 等待Timer到期
?? ?<-t.C
?? ?// 執(zhí)行任務(wù)
?? ?fmt.Println("Task executed at", time.Now())
}

# 輸出
Task executed at 2023-05-30 21:58:32.5390386 +0800 CST m=+2.002460501

8.2.2 Timer停止定時器

使用 time.Stop() 停止定時器,通過向通道發(fā)送一個信號,通知定時器是否關(guān)閉。

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?done := make(chan bool)
?? ?ticker := time.NewTimer(1 * time.Second)
?? ?go func() {
?? ??? ?for {
?? ??? ??? ?select {
?? ??? ??? ?case <-done:
?? ??? ??? ??? ?ticker.Stop()
?? ??? ??? ??? ?return
?? ??? ??? ?case <-ticker.C:
?? ??? ??? ??? ?fmt.Println("Hello World!")
?? ??? ??? ?}
?? ??? ?}
?? ?}()
?? ?time.Sleep(10 *time.Second)
?? ?done <- true
}

# 輸出
Hello World!

8.2.3 Timer重置定時器

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?fmt.Println("hello world", time.Now())
?? ?// 創(chuàng)建一個定時器
?? ?// 設(shè)置7秒后執(zhí)行一次
?? ?myT := time.NewTimer(7 * time.Second)
?? ?// 重置定時器為1s后執(zhí)行
?? ?myT.Reset(1 * time.Second)
?? ?<-myT.C
?? ?fmt.Println("hello world", time.Now())
}

# 輸出
hello world 2023-05-30 22:13:03.4342176 +0800 CST m=+0.002177501
hello world 2023-05-30 22:13:04.4454858 +0800 CST m=+1.013445701

8.2.4 Ticker啟動定時器

Ticker 也是定時器,它是一個周期性的定時器。

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?// 創(chuàng)建一個Ticker實例,每隔1秒執(zhí)行一次任務(wù)
?? ?ticker := time.NewTicker(1 * time.Second)
?? ?// 記得釋放Ticker資源
?? ?defer ticker.Stop()
?? ?// 循環(huán)處理任務(wù)
?? ?for {
?? ??? ?// 等待Ticker的下一次觸發(fā)
?? ??? ?<-ticker.C
?? ??? ?// 執(zhí)行任務(wù)
?? ??? ?fmt.Println("Task executed at", time.Now())
?? ?}
}

# 輸出
Task executed at 2023-05-30 22:17:57.2393424 +0800 CST m=+1.007115201
Task executed at 2023-05-30 22:17:58.2428548 +0800 CST m=+2.010627601
Task executed at 2023-05-30 22:17:59.2431966 +0800 CST m=+3.010969401
Task executed at 2023-05-30 22:18:00.2455851 +0800 CST m=+4.013357901
Task executed at 2023-05-30 22:18:01.2438882 +0800 CST m=+5.011661001
......

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?// 創(chuàng)建一個定時器,每隔1秒觸發(fā)一次
?? ?ticker := time.NewTicker(1 * time.Second)
?? ?// 在函數(shù)退出時停止定時器
?? ?defer ticker.Stop()
?? ?// timer實現(xiàn)定時器(延遲執(zhí)行),這個定時器只會觸發(fā)一次,所以想要執(zhí)行定時任務(wù)需要放在for循環(huán)中
?? ?for {
?? ??? ?select {
?? ??? ?// 定時器觸發(fā)時執(zhí)行的任務(wù)
?? ??? ?case <-ticker.C:
?? ??? ??? ?fmt.Println("hello world", time.Now())
?? ??? ?}
?? ?}
}

# 輸出
hello world 2023-05-30 21:15:42.32353 +0800 CST m=+42.004562601
hello world 2023-05-30 21:15:43.3274285 +0800 CST m=+43.008461101
hello world 2023-05-30 21:15:44.3226011 +0800 CST m=+44.003633701
hello world 2023-05-30 21:15:45.3233505 +0800 CST m=+45.004383101
hello world 2023-05-30 21:15:46.3310151 +0800 CST m=+46.012047701
hello world 2023-05-30 21:15:47.3234301 +0800 CST m=+47.004462701
hello world 2023-05-30 21:15:48.3243248 +0800 CST m=+48.005357401
......

8.2.5 Ticker停止定時器

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?ticker := time.NewTicker(1 * time.Second)
?? ?go func() {
?? ??? ?for range ticker.C {
?? ??? ??? ?fmt.Println("Hello World!")
?? ??? ?}
?? ?}()
?? ?time.Sleep(10 * time.Second)
?? ?ticker.Stop()
}

# 輸出
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

package main
import (
?? ?"fmt"
?? ?"time"
)
func main() {
?? ?done := make(chan bool)
?? ?ticker := time.NewTicker(1 * time.Second)
?? ?go func() {
?? ??? ?for {
?? ??? ??? ?select {
?? ??? ??? ?case <-done:
?? ??? ??? ??? ?ticker.Stop()
?? ??? ??? ??? ?return
?? ??? ??? ?case <-ticker.C:
?? ??? ??? ??? ?fmt.Println("Hello World!")
?? ??? ??? ?}
?? ??? ?}
?? ?}()
?? ?time.Sleep(10 *time.Second)
?? ?done <- true
}

# 輸出
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

8.3 gocron庫

8.3.1 安裝

go get -u github.com/go-co-op/gocron

8.3.2 使用

s := gocron.NewScheduler(time.UTC)
s.Every(5).Seconds().Do(func(){ ... }) 
s.Every("5m").Do(func(){ ... })
s.Every(5).Days().Do(fu
s.Every(1).Month(1, 2, 3).Do(func(){ ... })
s.Every(1).Day().At("10:30").Do(func(){ ... })
s.Every(1).Day().At("10:30;08:00").Do(func(){ ... })
s.Every(1).Day().At("10:30").At("08:00").Do(func(){ ... })
s.Every(1).MonthLastDay().Do(func(){ ... })
s.Every(2).MonthLastDay().Do(func(){ ... })
s.Cron("*/1 * * * *").Do(task) 
s.StartAsync()
s.StartBlocking()

8.3.3 例子

package main
import (
?? ?"fmt"
?? ?"time"
?? ?"github.com/go-co-op/gocron"
)
func cron1() {
?? ?fmt.Println("cron1",time.Now())
}
func cron2() {
?? ?fmt.Println("cron2",time.Now())
}
func main() {
?? ?timezone, _ := time.LoadLocation("Asia/Shanghai")
?? ?s := gocron.NewScheduler(timezone)
?? ?// 每秒執(zhí)行一次
?? ?s.Every(1).Seconds().Do(func() {
?? ??? ?go cron1()
?? ?})
?? ?// 每秒執(zhí)行一次
?? ?s.Every(1).Second().Do(func() {
?? ??? ?go cron2()
?? ?})
?? ?s.StartBlocking()
}

# 輸出
cron2 2023-05-30 22:28:09.1476998 +0800 CST m=+0.002582801
cron1 2023-05-30 22:28:09.1476998 +0800 CST m=+0.002582801
cron2 2023-05-30 22:28:10.1478397 +0800 CST m=+1.002722701
cron1 2023-05-30 22:28:10.1478397 +0800 CST m=+1.002722701
cron1 2023-05-30 22:28:11.1487562 +0800 CST m=+2.003639201
cron2 2023-05-30 22:28:11.1487562 +0800 CST m=+2.003639201
cron2 2023-05-30 22:28:12.1479533 +0800 CST m=+3.002836301
cron1 2023-05-30 22:28:12.1479533 +0800 CST m=+3.002836301
......

到此這篇關(guān)于Go語言定時任務(wù)的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Go語言定時任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • golang內(nèi)存對齊的項目實踐

    golang內(nèi)存對齊的項目實踐

    本文主要介紹了golang內(nèi)存對齊的項目實踐,內(nèi)存對齊不僅有助于提高內(nèi)存訪問效率,還確保了與硬件接口的兼容性,是Go語言編程中不可忽視的重要優(yōu)化手段,下面就來介紹一下
    2025-02-02
  • Golang中使用Mqtt的方法示例

    Golang中使用Mqtt的方法示例

    本文介紹了Golang中使用paho.mqtt.golang庫實現(xiàn)MQTT客戶端與服務(wù)器的連接、訂閱和消息收發(fā),具有一定的參考價值,感興趣的可以了解一下
    2025-02-02
  • 自己動手用Golang實現(xiàn)約瑟夫環(huán)算法的示例

    自己動手用Golang實現(xiàn)約瑟夫環(huán)算法的示例

    這篇文章主要介紹了自己動手用Golang實現(xiàn)約瑟夫環(huán)算法的示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Go語言異常處理案例解析

    Go語言異常處理案例解析

    這篇文章主要介紹了Go語言異常處理案例解析,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 一文搞懂Go語言標準庫strconv

    一文搞懂Go語言標準庫strconv

    strconv包實現(xiàn)了基本數(shù)據(jù)類型和其字符串表示的相互轉(zhuǎn)換,本文主要介紹Go語言標準庫strconv,想要學(xué)習(xí)strconv標準庫的可以了解一下
    2023-04-04
  • Go語言中interface語法與使用詳解

    Go語言中interface語法與使用詳解

    Go語言里面設(shè)計最精妙的應(yīng)該算interface,它讓面向?qū)ο?內(nèi)容組織實現(xiàn)非常的方便,下面這篇文章主要給大家介紹了關(guān)于Go語言中interface語法與使用的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • GO項目部署Linux服務(wù)器的實現(xiàn)示例

    GO項目部署Linux服務(wù)器的實現(xiàn)示例

    本文主要介紹了GO項目部署Linux服務(wù)器的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • Go語言中iota的具體使用

    Go語言中iota的具體使用

    Go語言中,iota是一個用于生成一系列相關(guān)常量值的常量生成器,常應(yīng)用于枚舉、位操作等場景,廣泛用于定義HTTP狀態(tài)碼、權(quán)限控制等,本文就來介紹一下iota的具體使用,感興趣的可以了解一下
    2024-11-11
  • 詳解Go語言中init的使用與常見應(yīng)用場景

    詳解Go語言中init的使用與常見應(yīng)用場景

    Go?中有一個特別的?init()?函數(shù),它主要用于包的初始化,這篇文章將以此為主題介紹?Go?中?init()?函數(shù)的使用和常見使用場景,希望對大家有所幫助
    2024-02-02
  • Goland字符串格式化樣式中“\r“的作用詳解

    Goland字符串格式化樣式中“\r“的作用詳解

    這篇文章主要介紹了Goland字符串格式化樣式中“\r“的作用,"\r"起的作用是回到行首,當前控制臺輸出,輸出完以后回到當前行的行首,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2023-04-04

最新評論