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

Go語言實(shí)現(xiàn)定時(shí)器的原理及使用詳解

 更新時(shí)間:2022年12月20日 10:54:58   作者:yuzhang_zy  
這篇文章主要為大家詳細(xì)介紹了Go語言實(shí)現(xiàn)定時(shí)器的兩種方法:一次性定時(shí)器(Timer)和周期性定時(shí)器(Ticker),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

0. 前言

在進(jìn)行并發(fā)編程時(shí),有時(shí)候會(huì)需要定時(shí)功能,比如監(jiān)控某個(gè)GO程是否會(huì)運(yùn)行過長時(shí)間、定時(shí)打印日志等等。

GO標(biāo)準(zhǔn)庫中的定時(shí)器主要有兩種,一種為Timer定時(shí)器,一種為Ticker定時(shí)器。Timer計(jì)時(shí)器使用一次后,就失效了,需要Reset()才能再次生效。而Ticker計(jì)時(shí)器會(huì)一直生效,接下來分別對(duì)兩種進(jìn)行介紹。

1. Timer定時(shí)器

首先介紹一下GO定時(shí)器的實(shí)現(xiàn)原理。

在一個(gè)GO進(jìn)程中,其中的所有計(jì)時(shí)器都是由一個(gè)運(yùn)行著 timerproc() 函數(shù)的 goroutine 來保護(hù)。它使用時(shí)間堆(最小堆)的算法來保護(hù)所有的 Timer,其底層的數(shù)據(jù)結(jié)構(gòu)基于數(shù)組的最小堆,堆頂?shù)脑厥情g隔超時(shí)最近的 Timer,這個(gè) goroutine 會(huì)定期 wake up,讀取堆頂?shù)?Timer,執(zhí)行對(duì)應(yīng)的 f 函數(shù)或者 sendtime()函數(shù)(下文會(huì)對(duì)這兩個(gè)函數(shù)進(jìn)行介紹),而后將其從堆頂移除。

接著看看Timer的結(jié)構(gòu):

type Timer struct {
    C <-chan Time
    // contains filtered or unexported fields
}

Timer中對(duì)外暴露的只有一個(gè)channel,這個(gè) channel 也是定時(shí)器的核心。當(dāng)計(jì)時(shí)結(jié)束時(shí),Timer會(huì)發(fā)送值到channel中,外部環(huán)境在這個(gè) channel 收到值的時(shí)候,就代表計(jì)時(shí)器超時(shí)了,可與select搭配執(zhí)行一些超時(shí)邏輯??梢酝ㄟ^time.NewTimer、time.AfterFunc或者 time.Afte對(duì)一個(gè)Timer進(jìn)行創(chuàng)建。

1.1 time.NewTimer() 和 time.After()

1.1.1 time.NewTimer()

查看以下簡單的應(yīng)用代碼:

package main

import (
   "fmt"
   "time"
)
type H struct {
   t *time.Timer
}

func main()  {
   fmt.Println("main")
   h:=H{t: time.NewTimer(1*time.Second)}
   go h.timer()
   time.Sleep(10*time.Second)
}

func (h *H) timer()  {
   for  {
      select {
      case <-h.t.C:
         fmt.Println("timer")
      }
   }

}

我們創(chuàng)建了一個(gè)timer,設(shè)置時(shí)間為1S。然后使用一個(gè)select對(duì)timer的C進(jìn)行接受,GO程運(yùn)行timer()函數(shù),會(huì)一直阻塞直到超時(shí)發(fā)生(接收到C的數(shù)據(jù)),此時(shí)打印timer。

Stop() 停止 Timer

func (t *Timer) Stop() bool

Stop() 是 Timer 的一個(gè)方法,調(diào)用 Stop()方法,會(huì)停止這個(gè) Timer 的計(jì)時(shí),使其失效,之后觸發(fā)定時(shí)事件。

實(shí)際上,調(diào)用此方法后,此Timer會(huì)被從時(shí)間堆中移除。

Reset()重置Timer

注意,Timer定時(shí)器超時(shí)一次后就不會(huì)再次運(yùn)行,所以需要調(diào)用Reset函數(shù)進(jìn)行重置。修改select中代碼,在Case中添加一個(gè)重置的代碼:

select {
case <-h.t.C:
   fmt.Println("timer")
   h.t.Reset(1*time.Second)
}

可以看到,會(huì)不停的打印timer,這是因?yàn)槭褂昧薘eset函數(shù)重置定時(shí)器。

注意!不能隨意的對(duì)Reset方法進(jìn)行調(diào)用,官網(wǎng)文檔中特意強(qiáng)調(diào):

For a Timer created with NewTimer, Reset should be invoked only on stopped or expired timers with drained channels.

大概的意思就是說,除非Timer已經(jīng)被停止或者超時(shí)了,否則不要調(diào)用Reset方法,因?yàn)?,如果這個(gè) Timer 還沒超時(shí),不先去Stop它,而是直接Reset,那么舊的 Timer 仍然存在,并且仍可能會(huì)觸發(fā),會(huì)產(chǎn)生一些意料之外的事。所以通常使用如下的代碼,安全的重置一個(gè)不知狀態(tài)的Timer(以上的代碼中,Reset調(diào)用時(shí),總是處于超時(shí)狀態(tài)):

if !t.Stop() {
    select {
    case <-h.t.C: 
    default:
    }
}
h.t.Reset(1*time.Second)

1.1.2 time.After()

此方法就像是一個(gè)極簡版的Timer使用,調(diào)用time.After(),會(huì)直接返回一個(gè)channel,當(dāng)超時(shí)后,此channel會(huì)接受到一個(gè)值,簡單使用如下:

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("main")
	go ticker()
	time.Sleep(100 * time.Second)
}

func ticker() {
	for {
		select {
		case <-time.After(1 * time.Second):
			fmt.Println("timer")
		}
	}
}

注意,此方法雖然簡單,但是沒有Reset方法來重置定時(shí)器,但是可以搭配for 和select的重復(fù)調(diào)用來模擬重置。

1.1.3 sendtime函數(shù)

NewTimer和After這兩種創(chuàng)建方法,會(huì)Timer在超時(shí)后,執(zhí)行一個(gè)標(biāo)準(zhǔn)庫中內(nèi)置的函數(shù):sendTime,來將當(dāng)前的時(shí)間發(fā)送到channel中。

1.2 time.AfterFunc

此方法可以接受一個(gè)func類型參數(shù),在計(jì)時(shí)結(jié)束后,會(huì)運(yùn)行此函數(shù),查看以下代碼,猜猜會(huì)出現(xiàn)什么結(jié)果?

package main

import (
   "fmt"
   "time"
)

func main() {
   fmt.Println("main")
   t := time.AfterFunc(1*time.Second, func() {
      fmt.Println("timer")
   })
   go timer(t)
   time.Sleep(10 * time.Second)
}
func timer(t *time.Timer) {
   select {
   case <-t.C:
      fmt.Println("123")
   }
}

結(jié)果只打印了main以及timer。這是因?yàn)榇朔椒ú⒉粫?huì)調(diào)用上文提到的sendtime()函數(shù),即不會(huì)發(fā)送值給Timer的Channel,所以select就會(huì)一直阻塞。

f函數(shù)

特意將AfterFunc和以上的NewTimer和After,就是因?yàn)閒函數(shù)的存在。這種方式創(chuàng)建的Timer,在到達(dá)超時(shí)時(shí)間后會(huì)在單獨(dú)的goroutine里執(zhí)行函數(shù)f,而不會(huì)執(zhí)行sendtime函數(shù)。

注意,外部傳入的f參數(shù)并非直接運(yùn)行在timerproc中,而是啟動(dòng)了一個(gè)新的goroutine去執(zhí)行此方法。

2. Ticker定時(shí)器

Ticker定時(shí)器可以周期性地不斷地觸發(fā)時(shí)間事件,不需要額外的Reset操作。

其使用方法與Timer大同小異。通過time.NewTicker對(duì)Ticker進(jìn)行創(chuàng)建,簡單的使用如下:

package main

import (
   "fmt"
   "time"
)

func main() {
   fmt.Println("main")
   t:=time.NewTicker(1*time.Second)
   go timer(t)
   time.Sleep(10 * time.Second)
}
func timer(t *time.Ticker) {
   for{
      select {
      case <-t.C:
         fmt.Println("timer")
      }
   }
}

到此這篇關(guān)于Go語言實(shí)現(xiàn)定時(shí)器的原理及使用詳解的文章就介紹到這了,更多相關(guān)Go語言定時(shí)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang并發(fā)之RWMutex的用法詳解

    Golang并發(fā)之RWMutex的用法詳解

    在?Go?語言中,RWMutex?是一種讀寫互斥鎖的實(shí)現(xiàn),它提供了一種簡單有效的方式來管理對(duì)共享資源的并發(fā)訪問。本文就來和大家詳細(xì)聊聊RWMutex的用法吧
    2023-04-04
  • go?mod?tidy報(bào)錯(cuò)解決方法詳解

    go?mod?tidy報(bào)錯(cuò)解決方法詳解

    這篇文章主要為大家介紹了go?mod?tidy報(bào)錯(cuò)解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語言實(shí)現(xiàn)AES加密并編寫一個(gè)命令行應(yīng)用程序

    Go語言實(shí)現(xiàn)AES加密并編寫一個(gè)命令行應(yīng)用程序

    密碼學(xué)中的高級(jí)加密標(biāo)準(zhǔn)(Advanced Encryption Standard,AES),又稱Rijndael加密法,是經(jīng)常采用的一種區(qū)塊加密標(biāo)準(zhǔn)。本文就來用Go語言實(shí)現(xiàn)AES加密算法,需要的可以參考一下
    2023-02-02
  • 深入理解Go gin框架中Context的Request和Writer對(duì)象

    深入理解Go gin框架中Context的Request和Writer對(duì)象

    這篇文章主要為大家詳細(xì)介紹了Go語言的gin框架中Context的Request和Writer對(duì)象,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語言有一定的幫助,快跟隨小編一起學(xué)習(xí)一下吧
    2023-04-04
  • Go工具鏈之代碼測試神器go?test詳解

    Go工具鏈之代碼測試神器go?test詳解

    這篇文章主要給大家介紹Go?工具鏈go?test,go?test?是?Go?工具鏈中的一個(gè)命令,用于編譯和運(yùn)行按照要求編寫的?Golang?測試代碼,并生成測試報(bào)告,感興趣的同學(xué)跟著小編一起來看看本文吧
    2023-07-07
  • Go語言中的值類型與引用類型的使用

    Go語言中的值類型與引用類型的使用

    Go語言中的數(shù)據(jù)類型可以分為值類型和引用類型,值類型包括基本和復(fù)合數(shù)據(jù)類型,特點(diǎn)是在傳遞時(shí)進(jìn)行復(fù)制,保證數(shù)據(jù)的安全性,引用類型如slice、map等,傳遞的是引用副本,便于大型數(shù)據(jù)操作且提高性能,理解這些概念有助于編寫更高效、安全的Go代碼
    2024-09-09
  • Golang調(diào)用FFmpeg轉(zhuǎn)換視頻流的實(shí)現(xiàn)

    Golang調(diào)用FFmpeg轉(zhuǎn)換視頻流的實(shí)現(xiàn)

    本文主要介紹了Golang調(diào)用FFmpeg轉(zhuǎn)換視頻流,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Go語言做爬蟲狀態(tài)碼返回418的問題解決

    Go語言做爬蟲狀態(tài)碼返回418的問題解決

    在使用Go語言做爬蟲時(shí),使用http.Get(url)去獲取網(wǎng)頁內(nèi)容,狀態(tài)碼返回404,本文我們就詳細(xì)的介紹一下解決方法,感興趣的可以了解一下
    2021-12-12
  • golang gorm中格式化時(shí)間問題詳解

    golang gorm中格式化時(shí)間問題詳解

    這篇文章主要給大家介紹了關(guān)于golang gorm中格式化時(shí)間問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 阿里云go開發(fā)環(huán)境搭建過程

    阿里云go開發(fā)環(huán)境搭建過程

    這篇文章主要介紹了阿里云go開發(fā)環(huán)境搭建過程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02

最新評(píng)論

万年县| 大邑县| 赣榆县| 秀山| 电白县| 阿克陶县| 卓资县| 和田市| 嘉义市| 鱼台县| 黑水县| 尼玛县| 苏尼特左旗| 始兴县| 南乐县| 常山县| 哈密市| 西昌市| 宣武区| 福贡县| 城口县| 台中县| 阿勒泰市| 从江县| 伊宁县| 贵阳市| 长寿区| 福建省| 嵩明县| 兴海县| 德安县| 香格里拉县| 芜湖县| 延津县| 纳雍县| 丹江口市| 翁牛特旗| 邵阳县| 凤凰县| 九龙坡区| 乾安县|