time.NewTicker()和time.Tick()的区别和用法
相信有很多小伙伴和本人一样刚开始学习GO语言时在使用定时器的时候都会一些疑惑:
time.NewTicker() 和 time.Tick()的功能是一样的
他们有什么区别呢?
什么时候该用time.NewTicker()?
什么时候该用time.Tick()?
今天就带着大家来一探究竟。
使用方式
time.NewTicker()
ticker := time.NewTicker(time.Second)
for {
select {
case <- ticker.C:
fmt.Println("wenjianjia")
}
}time.Tick():
for {
select {
case <- time.Tick(time.Second):
fmt.Println("wenjianjia")
}
}以上两段代码是很常用的情况,看上去两种的用法是差不多的,只是time.NewTicker()是再for循环外提前声明的。
但!真的是这样吗?
源码解析
time.NewTicker()
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
}
c := make(chan Time, 1)
t := &Ticker{
C: c,
r: runtimeTimer{
when: when(d),
period: int64(d),
f: sendTime,
arg: c,
},
}
startTimer(&t.r)
return t
}time.Tick():
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
}对比发现其实time.Tick只是对time.NewTicker的一个封装,底层其实还是调用了time.NewTicker(怪不得效果一样,恍然大悟···)。
接着我们结合time.Tick的实现和用法改进一下上面的写法:
for {
select {
// 暂不考虑异常情况
//if d <= 0 {
// return nil
//}
case <-time.NewTicker(d).C:
fmt.Println("wenjianjia")
}
}是不是发现问题了,如果在for循环里面使用time.Tick每次循环都是重新new一个Ticker出来,之前的也没有释放这不就造成泄露了吗。要是在一些需要长久循环的逻辑中使用了time.Tick后果不堪设想,这也是初学者比容容易犯的错误。
我们再来看下time.Tick的原文注释:
// 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.
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
}其实time.Tick的注释也写得很清楚了,大致的意思是:Tick是NewTicker的封装,只提供对ticking频道的访问。虽然Tick对于不需要关闭Ticker的客户端很有用,但要注意,如果没有关闭Ticker的方法,垃圾收集器将无法恢复底层的Ticker;将会造成内存泄露。与NewTicker不同,如果d<=0,Tick将返回nil。
总结
说了这么多了总结下来就四点:
- time.Tick是time.NewTicker的一个封装
- time.Tick用起来轻便简单但是不会销毁自身对象,适合在一次性的逻辑中使用
- time.NewTicker和time.Tick相比虽然多了些许的繁琐,但是始终是一个对象循环使用时不会造成泄露问题
- 在for循环中必须使用time.NewTicker如果使用time.Tick会造成内存泄露
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭