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

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

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

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

golang中定時器

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

一般用法:

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

設計我們的定時任務隊列

我的需求

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

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

定義結構

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

隊列實現(xiàn)

首先,我們要獲得一個隊列任務

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

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

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í)行 防止主進程被阻塞
}

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

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

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

 var d time.Duration
 if i64 < 0 { //如果任務時間已過期,將執(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 { 
      //當定時器到了執(zhí)行時間時,執(zhí)行當前任務并關閉定時器
 case <-timer.C:
 one.doAndReset(key)
 if task != nil {
  go task.Job.Run()
  timer.Stop()
 }

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

 break
 }
 }
}

后記

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

源碼地址:timing 一個任務隊列

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

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

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

相關文章

  • Golang簡單實現(xiàn)http的server端和client端

    Golang簡單實現(xiàn)http的server端和client端

    Http 服務是基于 Tcp 的應用層的實現(xiàn),也是最常見的網(wǎng)絡協(xié)議之一。本文主要介紹了Golang簡單實現(xiàn)http的server端和client端,感興趣的可以了解一下
    2021-06-06
  • golang將多路復異步io轉成阻塞io的方法詳解

    golang將多路復異步io轉成阻塞io的方法詳解

    常見的IO模型有阻塞、非阻塞、IO多路復用,異,下面這篇文章主要給大家介紹了關于golang將多路復異步io轉成阻塞io的方法,文中給出了詳細的示例代碼,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧。
    2017-09-09
  • golang等待觸發(fā)事件的實例

    golang等待觸發(fā)事件的實例

    這篇文章主要介紹了golang等待觸發(fā)事件的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang中單引號、雙引號、反引號的實現(xiàn)

    Golang中單引號、雙引號、反引號的實現(xiàn)

    Go語言中單引號表示rune類型,雙引號用于字符串支持轉義,反引號保留原始內(nèi)容且支持多行不轉義,三者區(qū)分關鍵在于字符處理方式與轉義規(guī)則,下面就來介紹一下
    2025-06-06
  • golang如何使用指針靈活操作內(nèi)存及unsafe包原理解析

    golang如何使用指針靈活操作內(nèi)存及unsafe包原理解析

    本文將深入探討unsafe包的功能和原理,同時,我們學習某種東西,一方面是為了實踐運用,另一方面則是出于功利性面試的目的,所以,本文還會為大家介紹unsafe?包的典型應用以及高頻面試題,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • Go1.21新增slices包的用法詳解

    Go1.21新增slices包的用法詳解

    Go?1.21新增的?slices?包提供了很多和切片相關的函數(shù),可以用于任何類型的切片,這篇文章主要來和大家介紹一下slices包中相關函數(shù)的用法,需要的可以參考一下
    2023-08-08
  • 深入探究Golang中l(wèi)og標準庫的使用

    深入探究Golang中l(wèi)og標準庫的使用

    Go?語言標準庫中的?log?包設計簡潔明了,易于上手,可以輕松記錄程序運行時的信息、調(diào)試錯誤以及跟蹤代碼執(zhí)行過程中的問題等。本文主要來深入探究?log?包的使用和原理,幫助讀者更好地了解和掌握它
    2023-05-05
  • Golang Mutex實現(xiàn)互斥的具體方法

    Golang Mutex實現(xiàn)互斥的具體方法

    Mutex是Golang常見的并發(fā)原語,在開發(fā)過程中經(jīng)常使用到,本文主要介紹了Golang Mutex實現(xiàn)互斥的具體方法,具有一定的參考價值,感興趣的可以了解一下
    2023-04-04
  • Go實現(xiàn)后臺任務調(diào)度系統(tǒng)的實例代碼

    Go實現(xiàn)后臺任務調(diào)度系統(tǒng)的實例代碼

    平常我們在開發(fā)API的時候,前端傳遞過來的大批數(shù)據(jù)需要經(jīng)過后端處理,如果后端處理的速度快,前端響應就快,反之則很慢,影響用戶體驗,為了解決這一問題,需要我們自己實現(xiàn)后臺任務調(diào)度系統(tǒng),本文將介紹如何用Go語言實現(xiàn)后臺任務調(diào)度系統(tǒng),需要的朋友可以參考下
    2023-06-06
  • 使用Go語言進行安卓開發(fā)的詳細教程

    使用Go語言進行安卓開發(fā)的詳細教程

    本文將介紹如何使用Go語言進行安卓開發(fā),我們將探討使用Go語言進行安卓開發(fā)的優(yōu)點、準備工作、基本概念和示例代碼,通過本文的學習,你將了解如何使用Go語言構建高效的安卓應用程序,需要的朋友可以參考下
    2023-11-11

最新評論

海伦市| 红原县| 金昌市| 静宁县| 西昌市| 阿克| 定结县| 如皋市| 新郑市| 开远市| 宣恩县| 茌平县| 屏边| 彝良县| 明光市| 邛崃市| 西峡县| 大埔县| 江西省| 通海县| 渭源县| 福海县| 滨海县| 老河口市| 沁水县| 光山县| 读书| 三门县| 盐源县| 高碑店市| 华容县| 湄潭县| 绵竹市| 公安县| 博乐市| 湘西| 集安市| 永寿县| 丰城市| 宜兴市| 司法|