6.11 计时器 | Go 语言原本 https://golang.design/under-the-hood/zh-cn/part2runtime/ch06sched/timer/
https://mp.weixin.qq.com/s/tkm9nYcyUxE2vUbplSO-pA
Go-Zero如何应对海量定时/延迟任务
原创 hxl@好未来 GoCN 2020-10-10
一个系统中存在着大量的调度任务,同时调度任务存在时间的滞后性,而大量的调度任务如果每一个都使用自己的调度器来管理任务的生命周期的话,浪费 cpu 的资源而且很低效。
本文来介绍 go-zero 中 延迟操作,它可能让开发者调度多个任务时,只需关注具体的业务执行函数和执行时间「立即或者延迟」。而 延迟操作,通常可以采用两个方案:
Timer:定时器维护一个优先队列,到时间点执行,然后把需要执行的 task 存储在 map 中
collection 中的 timingWheel ,维护一个存放任务组的数组,每一个槽都维护一个存储 task 的双向链表。开始执行时,计时器每隔指定时间执行一个槽里面的 tasks。
方案 2 把维护 task 从 优先队列 O(nlog(n)) 降到 双向链表 O(1),而执行 task 也只要轮询一个时间点的 tasks O(N),不需要像优先队列,放入和删除元素 O(nlog(n))。
我们先看看 go-zero 中自己对 timingWheel 的使用 :
// 2021/3/29 22:17 Shawn
package main
import (
"fmt"
"time"
)
func NOW() time.Time {
return time.Now()
}
func t() int {
fmt.Println("in-", NOW())
go func() {
fmt.Println("1-NewTimer", NOW())
i := 60
s := time.Duration(i) * time.Second
timer := time.NewTimer(s)
<-timer.C
fmt.Println("2-NewTimer", NOW())
}()
fmt.Println("leave", NOW())
return 123
}
func main() {
i := t()
fmt.Println("i=", i, NOW())
for {
}
}
in- 2021-07-09 16:18:09.3988014 +0800 CST m=+0.003173901
leave 2021-07-09 16:18:09.4144284 +0800 CST m=+0.018800901
i= 123 2021-07-09 16:18:09.4144284 +0800 CST m=+0.018800901
1-NewTimer 2021-07-09 16:18:09.4144284 +0800 CST m=+0.018800901
2-NewTimer 2021-07-09 16:19:09.4144658 +0800 CST m=+60.018838301
package main
import (
"fmt"
"time"
)
func NOW() time.Time {
return time.Now()
}
func t() int {
fmt.Println("in-", NOW())
go func() {
fmt.Println("1-NewTimer", NOW())
i := 60
s := time.Duration(i) * time.Second
timer := time.NewTimer(s)
<-timer.C
fmt.Println("2-NewTimer", NOW())
}()
fmt.Println("leave", NOW())
return 123
}
func main() {
i := t()
fmt.Println("i=", i, NOW())
//for {
//
//}
}
in- 2021-07-09 16:22:21.4064411 +0800 CST m=+0.003581001
leave 2021-07-09 16:22:21.4209835 +0800 CST m=+0.018123401
i= 123 2021-07-09 16:22:21.4209835 +0800 CST m=+0.018123401
import (
"fmt"
"time"
)
func NOW() time.Time {
return time.Now()
}
func t() int {
i := 123
fmt.Println("in-", NOW())
go func() {
fmt.Println("1-NewTimer", NOW())
s := time.Duration(60) * time.Second
timer := time.NewTimer(s)
<-timer.C
fmt.Println("2-NewTimer", NOW())
}()
fmt.Println("leave", NOW())
defer func() {
fmt.Println("defer", NOW())
i = 456
}()
return i
}
func t1() (i int) {
i = 123
fmt.Println("in-", NOW())
go func() {
fmt.Println("1-NewTimer", NOW())
s := time.Duration(60) * time.Second
timer := time.NewTimer(s)
<-timer.C
fmt.Println("2-NewTimer", NOW())
i = 789
}()
defer func() {
fmt.Println("defer", NOW())
i = 456
}()
fmt.Println("leave", NOW())
return
}
func main() {
i := t1()
fmt.Println("i=", i, NOW())
for {
}
}