golang time.Newtimer和time.NewTicker使用和不同
1. time.Newtimer是可以在没有强引用的时候被gc回收掉的。但是time.NewTicker必须在defer中使用stop来释放资源,否则资源永远不会被gc回收
2. time.Tick(d Duration) <-chan Time方法是存在资源泄漏的,见注释:
// Tick is a convenience wrapper for NewTicker providing access to the ticking // channel only. While Tick is useful for clients that have no need to shut down // the Ticker, be aware that without a way to shut it down the underlying // Ticker cannot be recovered by the garbage collector; it "leaks". // Unlike NewTicker, Tick will return nil if d <= 0.
这种只能用于no need to shut down的情况,因此一般是不应该使用这个的
相关区别:
1. timer是用于只执行一次延时获取能力的情况。如果要多次使用,需要结合reset。例如:
func TestCs2(t *testing.T) {
timer := time.NewTimer(2 * time.Second)
for {
select {
case t := <-timer.C:
timer.Reset(2 * time.Second)
fmt.Printf("time:%v\n", t)
}
}
}
2. timer的注释中明确说明了如果使用reset的正确用法。
func TestBf(t *testing.T) {
fmt.Printf("time:%v\n", time.Now())
timer := time.NewTimer(time.Second)
time.Sleep(2 * time.Second)
if !timer.Stop() {
<-timer.C
}
timer.Reset(5 * time.Second)
for {
x :=
<-timer.C
fmt.Printf("time:%v\n", x)
}
}
step1 没有进行if !timer.Stop()是因为reset的值和创建时的值都是2s。因此无需reset。
其他变更了reset值的情况,必须进行if !timer.Stop()的判断。
3. time.ticker是重复进行定时触发的。和time.timer一样,其实底层是从一个1个值的channel中获取定时触发的time值。问题在于,time.ticker的stop方法是没有返回bool值的。因此没有办法通过timer类似的
if !timer.Stop() { <-timer.C }
这种方式,将已经放入到channel中的数据取出。
因此
func TestCs(t *testing.T) {
fmt.Printf("time:%v\n", time.Now())
timer := time.NewTicker(time.Second)
defer timer.stop()
time.Sleep(2 * time.Second)
go func() {
for {
select {
case x := <-timer.C:
fmt.Printf("time:%v\n", x)
}
}
}()
timer.Reset(5 * time.Second)
time.Sleep(time.Hour)
}
类似以上代码,会打印出如下结果
time:2024-01-21 21:04:24.857927 +0800 +08 m=+0.011576126
time:2024-01-21 21:04:25.858828 +0800 +08 m=+1.012470209
time:2024-01-21 21:04:31.8597 +0800 +08 m=+7.013304418
time:2024-01-21 21:04:36.859213 +0800 +08 m=+12.012786126
第二次21:04:25,就是没有取出已经放入在channl中的数据导致的。
同样注意,即使是timer。不先进行if !timer.Stop() { <-timer.C },而是直接操作timer.Reset(5 * time.Second)也是可以的,只不过会和ticker的情况一样,如果是channel中已经触发过了的数据,没有被取出,会在取出的时候,第一次间隔还是reset前的时间间隔。