本篇文章将对go语言的标准包time.Timer进行介绍,附带部分应用实例
1. time.Timer介绍
- TImer的定义:
type Timer struct { C <-chan Time // contains filtered or unexported fields }
- 从上面的定义中可以看出,Timer是一个struct,内部包含有一个接受Time的的单向channel
- Timer对应了一个驱动事件(a single event),Timer的创建方式只有两种:
- NewTimer:
func NewTimer(d Duration) *Timer
,该方法接收一个Duration,返回一个Timer。当指定的时间间隔过去之后,返回的Timer会接收到一个Time。 - AfterFunc:
func AfterFunc(d Duration, f func()) *Timer
,该方法接收一个Duration以及一个func,返回一个Timer;AfterFunc会在Duration指定的时间间隔结束之后,在一个独立的goroutine中调用传入的func,而返回的Timer包含一个stop方法,可以用于在duration期间内终止func的调用
- NewTimer:
2. time.Timer的方法
- Reset:
func (t *Timer) Reset(d Duration) bool
,可以认为Reset方法是用于重定义一个已有Timer:- 对于用NewTimer方法定义的Timer,该方法只能够在该TImer处于stopped或expired(也就是初定义Duration已过,channel接受过时间的情况)下使用
- 注意在调用Reset方法前,一定要判断该TImer是否处于对应的可执行状态,如下所示:
注意,该过程不应该并发地与其他接受channel内容的操作并发执行
if !t.Stop() { <-t.C } t.Reset(d)
- 注意在调用Reset方法前,一定要判断该TImer是否处于对应的可执行状态,如下所示:
- 对于用AfterFunc方法定义的Timer,Reset方法的返回值具有一下意义:
- True:调用时Timer的func还没有执行,Reset会重调度该方法
- False:调用时Timer的func已经在执行或执行完成,Reset会调度该方法并使其在此执行;
注意:如果返回的是false,那么Reset不会保证上次执行的func已经执行完毕,也不会保证下次执行的func不与上次执行func并发执行;如果用户想要知道上次的func是否已经执行完毕,那么需要在func中设置对应的标志
- 对于用NewTimer方法定义的Timer,该方法只能够在该TImer处于stopped或expired(也就是初定义Duration已过,channel接受过时间的情况)下使用
- Stop:
func (t *Timer) Stop() bool
,Stop方法会阻止Timer被“激活”:- 返回True:如果成果停止了Timer
- 返回False:如果Timer已经被激活了或处于原来就处于Stop状态;
注意:为了防止因度对应channel产生的错误,Stop方法不会关闭对应的channel
- 为了保证在执行完Stop方法或TImer的channel是空的,可以对Stop方法的返回值进行检查,同时抽取channel的内容:
if !t.Stop() { <-t.C }
- 对于一个由AfterFunc定义的Timer,如果Stop方法的返回值时false,那么说明该Timer已经被激活了,而其中的func已经在另一个goroutine中执行或执行完成;Stop方法不会等待func执行完毕之后才返回,如果用户想要确定func是否已经执行完成,那么需要通过在func中设定对应的标志
3. 示例
- 示例一:Timer会在指定Duration之后接收到一个时间
6 package main
5
4 import "time"
3 import "fmt"
2
1 func main() {
7 t := time.NewTimer(time.Duration(3*time.Second))
1 time.Sleep(5*time.Second)
2 if !t.Stop() {
3 now := <-t.C
4 fmt.Println(now)
5 }
6 }
输出:2022-02-18 10:40:05.167702931 +0800 CST m=+3.002078547
- 示例二:用AfterFunc定义的Timer不会在Duration结束之后接收到时间,而是会在另一个goroutine中执行指定的func
18 package main
17
16 import (
15 "time"
14 "fmt"
13 )
12
11 func main() {
10 f := func() {
9 fmt.Println("function is invoked!")
8 }
7 t := time.AfterFunc(time.Duration(3*time.Second), f)
6 time.Sleep(5*time.Second)
5 if !t.Stop() {
4 // now := <-t.C
3 // fmt.Println(now)
2 // 上述操作会陷入死锁
1 // 这也说明了用AfterFunc定义的Timer在指定的Duration结束之后并不会接收到时间
19 }
1 }