Strcpy

Go 定时器的使用

源代码/数据集已上传到 Github - posts

在执行定时任务的场景,每隔几秒钟就会执行一次,触发任务。
go提供了time包,用来实现延时,只需要循环执行延时,就可以实现定时器功能。
但是关于它的使用和实现,需要具体分析一下。

实现原理

go的time包里面提供了两个函数用于延时,分别是func After(d Duration) <-chan Time func Tick(d Duration) <-chan Time。而他们分别调用func NewTimer(d Duration) *Timerfunc NewTicker(d Duration) *Ticker来实现这个延时的。两个函数的实现差异只在变量t的赋值上,NewTimer使用Timer实现,NewTicker使用Ticker实现。两个结构体的数据结构完全一样,因此他们实际实现的效果也是完全一致的。

NewTicker的实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
}
// Give the channel a 1-element time buffer.
// If the client falls behind while reading, we drop ticks
// on the floor until the client catches up.
c := make(chan Time, 1)
t := &Ticker{
C: c,
r: runtimeTimer{
when: when(d),
period: int64(d),
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}

Ticker实现

1
2
3
4
5
6
// A Ticker holds a channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
r runtimeTimer
}

Ticker实现只有两个参数:
C: 管道,上层应用根据此管道接收事件;
r: runtime定时器,该定时器即系统管理的定时器,对上层应用不可见;
这里应该按照层次来理解Timer数据结构,Timer.C即面向Timer用户的,Timer.r是面向底层的定时器实现。

Ticker.C管道每隔一个延时周期就会接收到一个事件,用于延时任务的触发。

实现一个延时

1
2
3
4
5
func main() {
fmt.Println(time.Now().Unix())
<-time.Tick(1*time.Second)
fmt.Println(time.Now().Unix())
}

实现一个定时器

1
2
3
4
5
6
7
func main() {
timer := time.NewTicker(time.Second)
for {
<-timer.C
fmt.Println(time.Now().Unix())
}
}

错误示例

1
2
3
4
5
6
7
8
func main() {
for {
select {
case <-time.After(time.Second):
fmt.Println(time.Now().Unix())
}
}
}

time.After内的方法实现一遍,输出每次的定时器的内存地址

1
2
3
4
5
6
7
8
9
10
11
12
func main() {
for {
select {
case <-(func() <-chan time.Time {
t := time.NewTicker(time.Second)
fmt.Printf("%p\n", t)
return t.C
})():

}
}
}

可以看到,每一次调用方法都会生成一个定时器,不断开辟内存空间。

正确示例

1
2
3
4
5
6
7
8
9
func main() {
t := time.NewTicker(time.Second)
for {
select {
case <-t.C:
fmt.Printf("%p\n", t)
}
}
}

结尾

重启可以解决99.9%的问题?!


edit this page last updated at 2022-02-02

Big Image