最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言定時任務cron的設計與使用

 更新時間:2023年11月06日 10:33:14   作者:小范真是一把好手  
這篇文章主要為大家詳細介紹了Go語言中定時任務cron的設計與使用,文中的示例代碼講解詳細,對我們深入掌握Go語言有一定的幫助,需要的可以參考下

一、Cron表達式

Field name   | Mandatory? | Allowed values  | Allowed special characters
----------   | ---------- | --------------  | --------------------------
Seconds      | Yes        | 0-59            | * / , -
Minutes      | Yes        | 0-59            | * / , -
Hours        | Yes        | 0-23            | * / , -
Day of month | Yes        | 1-31            | * / , - ?
Month        | Yes        | 1-12 or JAN-DEC | * / , -
Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?

Cron表達式的格式是通過六個字符表示:"1 * * * * *"。這六位數(shù)分別表示秒,分,小時,每月第幾天,月,每個星期第幾天;

在這里重點解釋一下特殊字符:

  • *:代表任意值;*在分鐘字段,表示每分鐘;
  • /:用來指定時間間隔,*/15在分鐘字段,表示每隔15分鐘;
  • ,:列出多個離散值,1,15在天字段,表示每月1號和15號;
  • -:定義某個范圍,9-17在小時字段,表示上午9點到下午5點,兩邊都是閉區(qū)間;
  • ?:表示無特定值。在Cron中,如果天數(shù)與星期的指定會互斥??聪旅鎯蓚€例子:

0 0 12 ? * WED - 表示每周三中午12點。關心星期,忽略天數(shù);

0 0 12 15 * ? - 表示每個月的第15天中午12點。關心天數(shù),忽略星期;

同時在"github.com/robfig/cron/v3"包中預定義的Schedule,如下所示:

Entry                  | Description                                | Equivalent To
-----                  | -----------                                | -------------
@yearly (or @annually) | Run once a year, midnight, Jan. 1st        | 0 0 0 1 1 *
@monthly               | Run once a month, midnight, first of month | 0 0 0 1 * *
@weekly                | Run once a week, midnight between Sat/Sun  | 0 0 0 * * 0
@daily (or @midnight)  | Run once a day, midnight                   | 0 0 0 * * *
@hourly                | Run once an hour, beginning of hour        | 0 0 * * * *

二、如何使用Cron包

func TestCron(t *testing.T) {
	c := cron.New(cron.WithSeconds())

	// 每分鐘第一秒執(zhí)行該任務
	c.AddFunc("1 * * * * *", func() {
		fmt.Println("Hello world!")
	})

    // 每10s執(zhí)行一次任務
	sh := cron.Every(10 * time.Second)
	c.Schedule(sh, cron.FuncJob(func() {
		fmt.Println("you are ok")
	}))

	go func() {
		ticker := time.NewTicker(time.Second * 4)
		for {
			select {
			case <-ticker.C:
				fmt.Println("length: ", len(c.Entries()))
			}
		}
	}()

	// c.Start()
	c.Start()

	// Wait for the Cron job to run
	time.Sleep(5 * time.Minute)

	// Stop the Cron job scheduler
	c.Stop()
}

上述示例代碼中,使用兩種創(chuàng)建定時任務的方式,分別是:

  • c.AddFunc()
  • c.Schedule()

cron包的使用非常簡單,你只需要提供Job以及其執(zhí)行的規(guī)則即可。

三、如何設計一個Cron

關于Cron,調(diào)用者所有的操作與系統(tǒng)執(zhí)行對應的任務之間是異步的。因此,對于調(diào)用者來說,系統(tǒng)用例如下:

更進一步,可以查看下Cron提供的API:

type Cron struct {
	// Has unexported fields.
}
    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.

func New(opts ...Option) *Cron
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error)
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error)
func (c *Cron) Entries() []Entry
func (c *Cron) Entry(id EntryID) Entry
func (c *Cron) Location() *time.Location
func (c *Cron) Remove(id EntryID)
func (c *Cron) Run()
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID
func (c *Cron) Start()
func (c *Cron) Stop() context.Context

調(diào)用者添加完所有任務之后,系統(tǒng)的處理流程如下(從后臺任務的角度看):

上述就是后臺任務的流程,簡化后的代碼如下:

func (c *Cron) run() {
	// Figure out the next activation times for each entry.
	now := c.now()

	for {
		// Determine the next entry to run.
		// 將所有任務,按照下一次運行時間排序
    sort.Sort(byTime(c.entries))
    
		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:
      	....
        // 添加任務到數(shù)組容器
        
    	 // 獲取當前時刻,Cron里面所有的定時任務
			case replyChan := <-c.snapshot:
				replyChan <- c.entrySnapshot()
				continue

    	// 停止Cron
			case <-c.stop:
      	...
				return

    	// 移除某個定時任務
			case id := <-c.remove:
        ....
				c.removeEntry(id)

			}

			break
		}
	}
}

四、學習點

1. 通過channel傳輸快照

func (c *Cron) Entries() []Entry {
    c.runningMu.Lock()
    defer c.runningMu.Unlock()

    // 如果Cron,正在運行,那么返回一個通道
    if c.running {
        replyChan := make(chan []Entry, 1)
        c.snapshot <- replyChan
        return <-replyChan
    }

    // 如果Cron,已經(jīng)結(jié)束了,直接返回所有Entry
    return c.entrySnapshot()
}

這種寫法特別有意思。當調(diào)用者想查看當前系統(tǒng)所有的任務時,系統(tǒng)返回的是一個通道,接著在通道中返回所有的數(shù)據(jù)。具體時序圖如下所示:

下面這個架構圖畫的不是很好,畫都畫了就放這吧。

2. 匹配規(guī)則

讀到cron這個項目,你是否有這樣的疑問?cron后臺任務根據(jù)調(diào)用給定的規(guī)則,如何執(zhí)行任務的呢?比如"* * * * 1 *",系統(tǒng)是如何知道每年的第一個月執(zhí)行相應的任務呢?下面代碼,以月份為例。

程序的大致流程:

  • 將月份規(guī)則轉(zhuǎn)化為二進制數(shù)值;
  • 通過當前時間不斷+1,直到匹配規(guī)則月份;

這里主要借助下面這個函數(shù):

func getBits(min, max, step uint) uint64 {
    var bits uint64

    // If step is 1, use shifts.
    if step == 1 {
        return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
    }

    // Else, use a simple loop.
    for i := min; i <= max; i += step {
        bits |= 1 << i
    }
    return bits
}

func TestGetBits(t *testing.T) {
    res := getBits(1, 3, 1)

    fmt.Printf("%d 的二進制表示是 %b\n", res, res)
}

3. 實現(xiàn)接口的函數(shù)

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

type FuncJob func()

func (f FuncJob) Run() { f() }

上述代碼定義Job接口、FuncJob類型,并且函數(shù)類型實現(xiàn)了Job接口。這種寫法很常見,比如http.HandleFunc。這樣寫的好處,能夠?qū)⒁粋€函數(shù)強轉(zhuǎn)之后直接丟到接口參數(shù)中,具體轉(zhuǎn)化流程如下:

func() 類型函數(shù) -- 強轉(zhuǎn):FuncJob(func()) -- FuncJob -- 可以丟進Job接口中;

到此這篇關于Go語言定時任務cron的設計與使用的文章就介紹到這了,更多相關Go定時任務cron內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Golang error使用場景介紹

    Golang error使用場景介紹

    我們在使用Golang時,不可避免會遇到異常情況的處理,與Java、Python等語言不同的是,Go中并沒有try...catch...這樣的語句塊,這個時候我們?nèi)绾尾拍芨玫奶幚懋惓D??本文來教你正確方法
    2023-03-03
  • 詳解Go中gin框架如何實現(xiàn)帶顏色日志

    詳解Go中gin框架如何實現(xiàn)帶顏色日志

    當我們在終端上(比如Goland)運行gin框架搭建的服務時,會發(fā)現(xiàn)輸出的日志是可以帶顏色的,那這是如何實現(xiàn)的呢?本文就來和大家簡單講講
    2023-04-04
  • Go語言實現(xiàn)配置熱加載的方法分享

    Go語言實現(xiàn)配置熱加載的方法分享

    web項目,經(jīng)常需要熱啟動各種各樣的配置信息,一旦這些服務發(fā)生變更,我們需要重新啟動web server,以使配置生效,實現(xiàn)配置熱加載,本文為大家整理了幾個方法實現(xiàn)這個需求,需要的可以參考下
    2023-05-05
  • Golang使用原生http實現(xiàn)中間件的代碼詳解

    Golang使用原生http實現(xiàn)中間件的代碼詳解

    中間件(middleware):常被用來做認證校驗、審計等,家常用的Iris、Gin等web框架,都包含了中間件邏輯,但有時我們引入該框架顯得較為繁重,本文將介紹通過golang原生http來實現(xiàn)中間件操作,需要的朋友可以參考下
    2024-05-05
  • Go語言中的UTF-8實現(xiàn)

    Go語言中的UTF-8實現(xiàn)

    這篇文章主要介紹了Go語言中的UTF-8實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Go語言利用heap實現(xiàn)優(yōu)先級隊列

    Go語言利用heap實現(xiàn)優(yōu)先級隊列

    這篇文章主要為大家詳細介紹了Go語言中heap的使用以及如何利用heap實現(xiàn)優(yōu)先級隊列的相關資料,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-05-05
  • 三種Golang數(shù)組拷貝的實現(xiàn)方式與性能分析

    三種Golang數(shù)組拷貝的實現(xiàn)方式與性能分析

    在?Golang?中,有多種方式可以進行數(shù)組的拷貝,本文將對其中的三種方式進行性能分析,并比較它們的優(yōu)缺點,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-06-06
  • Go語言的GOPATH與工作目錄詳解

    Go語言的GOPATH與工作目錄詳解

    這篇文章主要介紹了Go語言的GOPATH與工作目錄詳解,本文詳細講解了GOPATH設置、應用目錄結(jié)構、編譯應用等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • Go語言利用aicli實現(xiàn)輕松調(diào)用DeepSeek和ChatGPT

    Go語言利用aicli實現(xiàn)輕松調(diào)用DeepSeek和ChatGPT

    這篇文章主要為大家介紹了一款用Go語言編寫的AI助手客戶端庫——aicli,該庫不僅支持ChatGPT,還集成了DeepSeek,感興趣的小伙伴可以了解一下
    2025-03-03
  • Golang之模糊測試工具的使用

    Golang之模糊測試工具的使用

    本文主要介紹了Golang之模糊測試工具的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03

最新評論

剑河县| 齐齐哈尔市| 唐海县| 延津县| 罗甸县| 大冶市| 襄汾县| 扎赉特旗| 台湾省| 丹凤县| 尉氏县| 阳新县| 大同县| 赤壁市| 竹山县| 六枝特区| 三河市| 夏河县| 翁牛特旗| 固镇县| 墨脱县| 廊坊市| 大荔县| 四子王旗| 韶关市| 鄂托克前旗| 新晃| 哈巴河县| 通化市| 治县。| 保康县| 图木舒克市| 张家口市| 天峻县| 安庆市| 大悟县| 上思县| 秦皇岛市| 吴川市| 綦江县| 壶关县|