国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - golang time包下定時器的實現方法

golang time包下定時器的實現方法

2020-05-12 10:59諾唯 Golang

定時器的實現大家應該都遇到過,最近在學習golang,所以下面這篇文章主要給大家介紹了關于golang time包下定時器的實現方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。

golang time包

和python一樣,golang時間處理還是比較方便的,以下介紹了golang 時間日期,相關包 "time"的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹。

時間戳

當前時間戳

?
1
2
fmt.Println(time.Now().Unix())
# 1389058332

str格式化時間

當前格式化時間

?
1
2
fmt.Println(time.Now().Format("2006-01-02 15:04:05")) // 這是個奇葩,必須是這個時間點, 據說是go誕生之日, 記憶方法:6-1-2-3-4-5
# 2014-01-07 09:42:20

時間戳轉str格式化時間

?
1
2
3
str_time := time.Unix(1389058332, 0).Format("2006-01-02 15:04:05")
fmt.Println(str_time)
# 2014-01-07 09:32:12

str格式化時間轉時間戳

這個比較麻煩

?
1
2
3
4
the_time := time.Date(2014, 1, 7, 5, 50, 4, 0, time.Local)
unix_time := the_time.Unix()
fmt.Println(unix_time)
# 389045004

還有一種方法,使用time.Parse

?
1
2
3
4
5
6
the_time, err := time.Parse("2006-01-02 15:04:05", "2014-01-08 09:04:41")
if err == nil {
unix_time := the_time.Unix()
fmt.Println(unix_time)
}
# 1389171881

以上簡單介紹了golang中time包的相關內容,下面開始本文的正文。

引言

這篇文章簡單的介紹下golang time 包下定時器的實現,說道定時器,在我們開發過程中很常用,由于使用的場景不同,所以對定時器實際的實現也就不同,go的定時器并沒有使用SIGALARM信號實現,而是采取最小堆的方式實現(源碼包中使用數組實現的四叉樹),使用這種方式定時精度很高,但是有的時候可能我們不需要這么高精度的實現,為了更高效的利用資源,有的時候也會實現一個精度比較低的算法。

跟golang定時器相關的入口主要有以下幾種方法:

?
1
2
3
4
5
6
<-time.Tick(time.Second)
<-time.After(time.Second)
<-time.NewTicker(time.Second).C
<-time.NewTimer(time.Second).C
time.AfterFunc(time.Second, func() { /*do*/ })
time.Sleep(time.Second)

這里我們以其中NewTicker為入口,NewTicker的源碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func NewTicker(d Duration) *Ticker {
 if d <= 0 {
 panic(errors.New("non-positive interval for NewTicker"))
 }
 c := make(chan Time, 1)
 t := &Ticker{
 C: c,
 r: runtimeTimer{
 // when(d)返回一個runtimeNano() + int64(d)的未來時(到期時間)
 //runtimeNano運行時當前納秒時間
 when: when(d),
 period: int64(d), // 被喚醒的時間
 f:  sendTime, // 時間到期后的回調函數
 arg: c,  // 時間到期后的斷言參數
 },
 }
 // 將新的定時任務添加到時間堆中
 // 編譯器會將這個函數翻譯為runtime.startTimer(t *runtime.timer)
 // time.runtimeTimer翻譯為runtime.timer
 startTimer(&t.r)
 return t

這里有個比較重要的是startTimer(&t.r)它的實現被翻譯在runtime包內

?
1
2
3
4
5
6
7
8
9
10
11
12
func startTimer(t *timer) {
 if raceenabled {
 racerelease(unsafe.Pointer(t))
 }
 addtimer(t)
}
 
func addtimer(t *timer) {
 lock(&timers.lock)
 addtimerLocked(t)
 unlock(&timers.lock)
}

上面的代碼為了看著方便,我將他們都放在一起

下面代碼都寫出部分注釋

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// 使用鎖將計時器添加到堆中
// 如果是第一次運行此方法則啟動timerproc
func addtimerLocked(t *timer) {
 if t.when < 0 {
 t.when = 1<<63 - 1
 }
 // t.i i是定時任務數組中的索引
 // 將新的定時任務追加到定時任務數組隊尾
 t.i = len(timers.t)
 timers.t = append(timers.t, t)
 // 使用數組實現的四叉樹最小堆根據when(到期時間)進行排序
 siftupTimer(t.i)
 // 如果t.i 索引為0
 if t.i == 0 {
 if timers.sleeping {
 // 如果還在sleep就喚醒
 timers.sleeping = false
 // 這里基于OS的同步,并進行OS系統調用
 // 在timerproc()使goroutine從睡眠狀態恢復
 notewakeup(&timers.waitnote)
 }
 if timers.rescheduling {
 timers.rescheduling = false
 // 如果沒有定時器,timerproc()與goparkunlock共同sleep
 // goready這里特殊說明下,在線程創建的堆棧,它比goroutine堆棧大。
 // 函數不能增長堆棧,同時不能被調度器搶占
 goready(timers.gp, 0)
 }
 }
 if !timers.created {
 timers.created = true
 go timerproc() //這里只有初始化一次
 }
}
 
// Timerproc運行時間驅動的事件。
// 它sleep到計時器堆中的下一個。
// 如果addtimer插入一個新的事件,它會提前喚醒timerproc。
func timerproc() {
 timers.gp = getg()
 for {
 lock(&timers.lock)
 timers.sleeping = false
 now := nanotime()
 delta := int64(-1)
 for {
 if len(timers.t) == 0 {
 delta = -1
 break
 }
 t := timers.t[0]
 delta = t.when - now
 if delta > 0 {
 break // 時間未到
 }
 if t.period > 0 {
 // 計算下一次時間
        // period被喚醒的間隔
 t.when += t.period * (1 + -delta/t.period)
 siftdownTimer(0)
 } else {
 // remove from heap
 last := len(timers.t) - 1
 if last > 0 {
  timers.t[0] = timers.t[last]
  timers.t[0].i = 0
 }
 timers.t[last] = nil
 timers.t = timers.t[:last]
 if last > 0 {
  siftdownTimer(0)
 }
 t.i = -1 // 標記移除
 }
 f := t.f
 arg := t.arg
 seq := t.seq
 unlock(&timers.lock)
 if raceenabled {
 raceacquire(unsafe.Pointer(t))
 }
 f(arg, seq)
 lock(&timers.lock)
 }
 if delta < 0 || faketime > 0 {
 // 沒有定時器,把goroutine sleep。
 timers.rescheduling = true
 // 將當前的goroutine放入等待狀態并解鎖鎖。
 // goroutine也可以通過呼叫goready(gp)來重新運行。
 goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
 continue
 }
 // At least one timer pending. Sleep until then.
 timers.sleeping = true
 timers.sleepUntil = now + delta
 // 重置
 noteclear(&timers.waitnote)
 unlock(&timers.lock)
 // 使goroutine進入睡眠狀態,直到notewakeup被調用,
 // 通過notewakeup 喚醒
 notetsleepg(&timers.waitnote, delta)
 }
}

golang使用最小堆(最小堆是滿足除了根節點以外的每個節點都不小于其父節點的堆)實現的定時器。golang []*timer結構如下:

golang time包下定時器的實現方法

golang存儲定時任務結構

addtimer在堆中插入一個值,然后保持最小堆的特性,其實這個結構本質就是最小優先隊列的一個應用,然后將時間轉換一個絕對時間處理,通過睡眠和喚醒找出定時任務,這里閱讀起來源碼很容易,所以只將代碼和部分注釋寫出。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://zhuanlan.zhihu.com/p/31634188

延伸 · 閱讀

精彩推薦
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: av官网在线 | 91国自产精品中文字幕亚洲 | 激情婷婷 | 毛片视频免费播放 | 一区二区三区视频 | 精品国产乱码久久久久久影片 | 黄在线 | www.涩涩视频 | 日韩免费| 在线中文字幕视频 | 国产欧美成人 | 午夜激情视频在线观看 | 日韩精品一区二区三区四区五区 | 日韩一区二区在线播放 | 亚洲国产精品一区 | 国产精品亚洲视频 | 羞羞av | 国产日韩精品一区二区 | 欧美日韩精品一区二区在线观看 | 国产成年人视频 | 毛片xxx | 人人九九精 | 欧美国产在线观看 | 国产在线视频网 | 台湾黄色网| 在线亚洲一区 | 成人a级片在线观看 | 成人网av| 亚洲人成免费网站 | 特黄特黄的视频 | 黄毛片网站 | 羞羞视频在线看 | 亚洲一卡二卡 | 不卡视频一二三区 | 免费在线黄色电影 | 欧美久久久 | 欧美一区二区三区视频在线 | 欧美精品99| 人人99精| 天天夜操 | 国产精品一区二区三区不卡 |