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秒后才会触发