> 文章列表 > go time.NewTimer 注意事项

go time.NewTimer 注意事项

go time.NewTimer 注意事项

使用go time的注意事项

    • time的常见用法介绍
          • 1. timer := time.NewTimer(time.Second * 2)
          • 2. res := timer.Stop()
          • 3. <-timer.C
          • 4. res := timer.Reset(time.Second * 3)
    • time的使用推荐方案
    • time的细节推敲
          • 细节1
          • 细节2
          • 细节3 推荐使用方案
    • 总结
            • 具体实现细节可以查看官方的实现,从介绍中去推敲和测试,进而比较深入的认知其实现。

time的常见用法介绍

1. timer := time.NewTimer(time.Second * 2)

注册一个计时器,两秒之后,会向timer.C中写入一个数据

2. res := timer.Stop()

停止定时器的触发,如果已经触发过了,返回false,否则返回true,可以理解成有没有成功阻止触发该计时器
注意:该操作只会尝试阻止触发,不会删除定时器中的channel

3. <-timer.C

从定时器的channel中获取一个值,等待计时器被触发时,会自动往该channel中写入数据

4. res := timer.Reset(time.Second * 3)

重置一个计时器,三秒之后会被触发,如果该定时器还没有被触发,返回true,否则返回false

time的使用推荐方案

func Run() {timer := time.NewTimer(time.Second * 1)ch := make(chan bool, 1)go func() {for {ch <- truetime.Sleep(time.Second * 1)}}()for {res := timer.Reset(time.Second * 1)fmt.Println("timer reset", res, time.Now().Unix())fmt.Println("")fmt.Println("-----------------------")select {case _, ok := <-timer.C:if ok {fmt.Println("time c", time.Now().Unix())} else {fmt.Println("time c not ok", time.Now().Unix())}case <-ch:res := timer.Stop()fmt.Println("ch timer stop", res, time.Now().Unix())}}
}

time的细节推敲

细节1
func Run() {timer := time.NewTimer(time.Second * 1)time.Sleep(2 * time.Second)res := timer.Stop()fmt.Println(res, time.Now().Unix())timer.Reset(time.Second * 3)fmt.Println("reset c", time.Now().Unix())<-timer.Cfmt.Println("time c", time.Now().Unix())// <-timer.Cfmt.Println("game Over", time.Now().Unix())
}
控制台输出内容:
PS D:\\code\\cursor_files> go run main.go
false 1681903204		-> false 已经触发过了
reset c 1681903204  	-> 所有的时间都相同,是因为timer虽然被重置,
time c 1681903204   	-> 但timer.C中的值是存在的,所以能立即获取到
game Over 1681903204
细节2
func Run() {timer := time.NewTimer(time.Second * 1)time.Sleep(2 * time.Second)res := timer.Stop()fmt.Println(res, time.Now().Unix())timer.Reset(time.Second * 3)fmt.Println("reset c", time.Now().Unix())<-timer.Cfmt.Println("time c", time.Now().Unix())<-timer.Cfmt.Println("game Over", time.Now().Unix())
}
控制台输出内容:
PS D:\\code\\cursor_files> go run main.go
false 1681903457		-> false 已经触发过了
reset c 1681903457  	-> 最后的时间和之前的相差3秒,是因为同1的情况,
time c 1681903457   	-> 第二次从timer.C中获取值时,因为定时器的时间还没有到,
game Over 1681903460	-> 所以会等待3秒后才会触发
细节3 推荐使用方案
func Run() {timer := time.NewTimer(time.Second * 1)time.Sleep(2 * time.Second)// <-timer.C // 从timer中把数据取出来了res := timer.Stop()fmt.Println(res, time.Now().Unix())// 推荐这种写法,确保在停止后,重置前,timer.C中的数据被取出,从而避免重置timer后,会立即触发的问题if !res {select {case <-timer.C:fmt.Println("1111")default:}}timer.Reset(time.Second * 3)fmt.Println("reset c", time.Now().Unix())<-timer.Cfmt.Println("time c", time.Now().Unix())// <-timer.C // 如果再次打开,将会因为无人在往timer.C中写入数据,导致主线程死锁异常fmt.Println("game Over", time.Now().Unix())
}
控制台输出内容:
PS D:\\code\\cursor_files> go run main.go
false 1681904597		-> false 已经触发过了
reset c 1681904597  	-> stop之后,如果是关闭的已经触发过的定时器,就会先尝试非阻塞的从timer.C
time c 1681904600   	-> 中读取,第二次从timer.C中获取值时,因为定时器的时间还没有到,
game Over 1681904600	-> 所以会等待3秒后才会触发

总结

具体实现细节可以查看官方的实现,从介绍中去推敲和测试,进而比较深入的认知其实现。