您现在的位置是:首页 >其他 >go time.NewTimer 注意事项网站首页其他
go time.NewTimer 注意事项
简介go time.NewTimer 注意事项
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 <- true
time.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:
// 推荐手动调用关闭timer,虽然timer从长远的角度看不会内存泄漏,但它的释放时间比较久,调用停止后,可以加快它的释放时间
// 这个非常重要,也是项目中遇到的坑
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.C
fmt.Println("time c", time.Now().Unix())
// <-timer.C
fmt.Println("game Over", time.Now().Unix())
}
控制台输出内容:
PS D:codecursor_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.C
fmt.Println("time c", time.Now().Unix())
<-timer.C
fmt.Println("game Over", time.Now().Unix())
}
控制台输出内容:
PS D:codecursor_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.C
fmt.Println("time c", time.Now().Unix())
// <-timer.C // 如果再次打开,将会因为无人在往timer.C中写入数据,导致主线程死锁异常
fmt.Println("game Over", time.Now().Unix())
}
控制台输出内容:
PS D:codecursor_files> go run main.go
false 1681904597 -> false 已经触发过了
reset c 1681904597 -> stop之后,如果是关闭的已经触发过的定时器,就会先尝试非阻塞的从timer.C
time c 1681904600 -> 中读取,第二次从timer.C中获取值时,因为定时器的时间还没有到,
game Over 1681904600 -> 所以会等待3秒后才会触发
总结
具体实现细节可以查看官方的实现,从介绍中去推敲和测试,进而比较深入的认知其实现。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。