亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

用golang實現(xiàn)一個定時器任務(wù)隊列實例

 更新時間:2018年05月23日 09:54:13   作者:o0無憂亦無怖  
golang中提供了2種定時器timer和ticker,分別是一次性定時器和重復(fù)任務(wù)定時器。這篇文章主要介紹了用golang實現(xiàn)一個定時器任務(wù)隊列實例,非常具有實用價值,需要的朋友可以參考下

 很有幸得到公司信任,采用新的語言進(jìn)行一些底層服務(wù)的開發(fā),在實現(xiàn)功能的同時,也獲得了一些感悟,因此在這記錄一下,方便自己查看也可以共享給大家。

golang中定時器

golang中提供了2種定時器timer和ticker(如果JS很熟悉的話應(yīng)該會很了解),分別是一次性定時器和重復(fù)任務(wù)定時器。

一般用法:

func main() { 
 input := make(chan interface{}) 
 //producer - produce the messages
 go func() {
  for i := 0; i < 5; i++ {
   input <- i
  }
  input <- "hello, world"
 }()
 
 t1 := time.NewTimer(time.Second * 5)
 t2 := time.NewTimer(time.Second * 10)
 
 for {
  select {
  //consumer - consume the messages
  case msg := <-input:
   fmt.Println(msg)
 
  case <-t1.C:
   println("5s timer")
   t1.Reset(time.Second * 5)
 
  case <-t2.C:
   println("10s timer")
   t2.Reset(time.Second * 10)
  }
 }
}

源碼觀察

這個C是啥,我們?nèi)ピ创a看看,以timer為例:

type Timer struct {
 C <-chan Time
 r runtimeTimer
}

原來是一個channel,其實有GO基礎(chǔ)的都知道,GO的運算符當(dāng)出現(xiàn)的->或者<-的時候,必然是有一端是指channel。按照上面的例子來看,就是阻塞在一個for循環(huán)內(nèi),等待到了定時器的C從channel出來,當(dāng)獲取到值的時候,進(jìn)行想要的操作。

設(shè)計我們的定時任務(wù)隊列

我的需求

當(dāng)時我的需求是這樣,我需要接收到客戶端的請求并產(chǎn)生一個定時任務(wù),會在固定時間執(zhí)行,可能是一次,也可能是多次,也可能到指定時間自動停止,可能當(dāng)任務(wù)終止的時候,我還要能停止掉。

具體我畫了個流程圖,差不多如下,畫圖水平有限,請見諒。

定義結(jié)構(gòu)

type OnceCron struct {
 tasks []*Task   //任務(wù)的列隊
 add chan *Task  //當(dāng)遭遇到新任務(wù)的時候
 remove chan string  //當(dāng)遭遇到刪除任務(wù)的時候
 stop chan struct{}  //當(dāng)遇到停止信號的時候
 Logger *log.Logger  //日志 
}
type Job interface {
 Run()     //執(zhí)行接口
}
type Task struct {
  Job  Job   //要執(zhí)行的任務(wù) 
 Uuid string   //任務(wù)標(biāo)識,刪除時用
 RunTime int64   //執(zhí)行時間
 Spacing int64   //間隔時間
 EndTime int64   //結(jié)束時間
 Number int    //總共要次數(shù)
}

隊列實現(xiàn)

首先,我們要獲得一個隊列任務(wù)

func NewCron() *OnceCron 常規(guī)操作,為了節(jié)省篇幅,我就不寫出來,具體可以看源碼,貼在了底部。

然后,開始定時器隊列的運行,一般,都會命名為Start。那么就有一個問題,我們剛開始啟動程序的時候,這個時候是沒有任務(wù)隊列,那豈不是for{ select{}}在等待個毛毛球?所以,我們需要在Start的時候添加一個默認(rèn)的任務(wù), 我是這么做的,添加了一個一小時執(zhí)行一次的重復(fù)隊列,防止隊列退出。

func (one *OnceCron) Start() {
 //初始化的時候加入一個一年的長定時器,間隔1小時執(zhí)行一次
 task := getTaskWithFuncSpacing(3600, time.Now().Add(time.Hour*24*365).Unix() , func() {
 log.Println("It's a Hour timer!")
 }) //為了代碼格式markdown 里面有個括號我改成全角了
 one.tasks = append(one.tasks, task)
 go one.run() //協(xié)成執(zhí)行 防止主進(jìn)程被阻塞
}

執(zhí)行部分應(yīng)該是重點的,我的理解是,分成三部:

  1. 首先獲得一個最先執(zhí)行的任務(wù)
  2. 然后產(chǎn)生一個定時器,用于執(zhí)行任務(wù)
  3. 進(jìn)行阻塞判斷,獲取我們要進(jìn)行的操作
func (one *OnceCron) run() {

 for {
    //第一步 獲取任務(wù)
 now := time.Now() //獲取到當(dāng)前時間
 task, key := one.GetTask() //獲取最近的一個任務(wù)的執(zhí)行時間
 i64 := task.RunTime - now.Unix() //任務(wù)執(zhí)行和當(dāng)前時間的差

 var d time.Duration
 if i64 < 0 { //如果任務(wù)時間已過期,將執(zhí)行時間改成現(xiàn)在并且利馬執(zhí)行
 one.tasks[key].RunTime = now.Unix() 
 one.doAndReset(key)
      continue
 } else { //否則,獲取距離執(zhí)行開始的間隔時間
 d = time.Unix(task.RunTime, 0).Sub(now)
 }
    //第二步 產(chǎn)生定時器
 timer := time.NewTimer(d) 

 //第三步 捕獲定時器或者其他事件
 for {
 select { 
      //當(dāng)定時器到了執(zhí)行時間時,執(zhí)行當(dāng)前任務(wù)并關(guān)閉定時器
 case <-timer.C:
 one.doAndReset(key)
 if task != nil {
  go task.Job.Run()
  timer.Stop()
 }

 //當(dāng)外部添加了任務(wù)時,關(guān)閉當(dāng)前定時器
 case <-one.add:
 timer.Stop()
 //當(dāng)外部要刪除一個任務(wù)時,刪除ID為uuidstr的任務(wù)
 case uuidstr := <-one.remove:
 one.removeTask(uuidstr)
 timer.Stop()
 //當(dāng)遇到要關(guān)閉整個定時器任務(wù)時
 case <-one.stop:
 timer.Stop()
 return
 }

 break
 }
 }
}

后記

這個文章純粹為筆記分析類的文章,旨在分析我碰到一個需求是如何通過分析過程來產(chǎn)生我們需要的代碼的。

源碼地址:timing 一個任務(wù)隊列

應(yīng)用地址:一個應(yīng)用于谷歌消息推送的轉(zhuǎn)發(fā)中間件

參考源碼:GOLANG實現(xiàn)crontab功能

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 深入探究Golang中flag標(biāo)準(zhǔn)庫的使用

    深入探究Golang中flag標(biāo)準(zhǔn)庫的使用

    在本文中,我們將深入探討 flag 標(biāo)準(zhǔn)庫的實現(xiàn)原理和使用技巧,以幫助讀者更好地理解和掌握該庫的使用方法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-04-04
  • Go的gin參數(shù)校驗中的validator庫詳解

    Go的gin參數(shù)校驗中的validator庫詳解

    這篇文章主要介紹了Go的gin參數(shù)校驗之validator庫,使用 validator 以后,只需要在定義結(jié)構(gòu)體時使用 binding 或 validate tag標(biāo)識相關(guān)校驗規(guī)則,就可以進(jìn)行參數(shù)校驗了,而不用自己單獨去寫常見的校驗規(guī)則,需要的朋友可以參考下
    2023-08-08
  • Golang使用Swagger文檔教程詳解

    Golang使用Swagger文檔教程詳解

    這篇文章主要為大家詳細(xì)介紹Golang使用Swagger文檔教程的相關(guān)知識,文中通過示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以學(xué)習(xí)一下
    2023-12-12
  • 一文搞懂Go語言中defer關(guān)鍵字的使用

    一文搞懂Go語言中defer關(guān)鍵字的使用

    defer是golang中用的比較多的一個關(guān)鍵字,也是go面試題里經(jīng)常出現(xiàn)的問題。今天就來整理一下關(guān)于defer的學(xué)習(xí)使用,希望對需要的朋友有所幫助
    2022-09-09
  • 詳解Go內(nèi)存模型

    詳解Go內(nèi)存模型

    這篇文章主要介紹了Go 內(nèi)存模型的相關(guān)資料,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • GO 函數(shù)式選項模式(Functional Options Pattern)

    GO 函數(shù)式選項模式(Functional Options Pattern)

    Option模式支持傳遞多個參數(shù),并且在參數(shù)個數(shù)、類型發(fā)生變化時保持兼容性,任意順序傳遞參數(shù),下面給大家介紹GO 函數(shù)式選項模式(Functional Options Pattern)的相關(guān)知識,感興趣的朋友一起看看吧
    2021-10-10
  • Go語言基礎(chǔ)函數(shù)包的使用學(xué)習(xí)

    Go語言基礎(chǔ)函數(shù)包的使用學(xué)習(xí)

    本文通過一個實現(xiàn)加減乘除運算的小程序來介紹go函數(shù)的使用,以及使用函數(shù)的注意事項,并引出了對包的了解和使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • go并發(fā)數(shù)據(jù)一致性事務(wù)的保障面試應(yīng)答

    go并發(fā)數(shù)據(jù)一致性事務(wù)的保障面試應(yīng)答

    這篇文章主要為大家介紹了go并發(fā)數(shù)據(jù)一致性事務(wù)的保障面試應(yīng)答,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • golang中http請求的context傳遞到異步任務(wù)的坑及解決

    golang中http請求的context傳遞到異步任務(wù)的坑及解決

    這篇文章主要介紹了golang中http請求的context傳遞到異步任務(wù)的坑及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Go并發(fā)編程結(jié)構(gòu)體多字段原子操作示例詳解

    Go并發(fā)編程結(jié)構(gòu)體多字段原子操作示例詳解

    這篇文章主要為大家介紹了Go并發(fā)編程結(jié)構(gòu)體多字段原子操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12

最新評論