Golang正确停止Ticker

Golang可以利用time包的Ticker实现定时器的作用,最近使用Ticker时,发现调用Ticker的Stop方法无法正确的停止Ticker,协程会阻塞在等待Ticker的C通道处,精简后的代码如下:

func UseTickerWrong() *time.Ticker {
	ticker := time.NewTicker(5 * time.Second)
	go func(ticker *time.Ticker) {
		for range ticker.C {
			fmt.Println("Ticker1....")
		}
		
		fmt.Println("Ticker1 Stop")
	}(ticker)
	
	return ticker
}

函数中我们创建一个5s的定时器,然后启动协程,在协程中我们读取Ticker的C通道,当定时时间到达时,该通道就会读到数据。我们在主函数中调用

func main() {
	ticker1 := UseTickerWrong()
	time.Sleep(20 * time.Second)
	ticker1.Stop()
}

输出结果为:

Ticker1…
Ticker1…
Ticker1…
Ticker1…

并没有最后的Ticker1 Stop,查看Ticker的Stop方法的说明会发现:

// Stop turns off a ticker. After Stop, no more ticks will be sent.
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.

翻一下就是Stop会停止Ticker,停止后,Ticker不会再被发送,但是Stop不会关闭通道,防止读取通道发生错误。

Golang中从已经关闭的通道读取数据会发生错误,Ticker的通道不关闭,防止我们在不必要的时候读取了已经关闭的通道。那么,到底如何科学的停止ticker呢?可以看看下面的函数

func UserTicker() chan bool {
	ticker := time.NewTicker(5 * time.Second)
	
	stopChan := make(chan bool)
	go func(ticker *time.Ticker) {
		defer ticker.Stop()
		
		for {
			select {
				case <-ticker.C:
					fmt.Println("Ticker2....")
				case stop := <-stopChan:
					if stop {
						fmt.Println("Ticker2 Stop")
						return
					}
			}
		}
	}(ticker)
	
	return stopChan
}

我们通过select读取两个通道,当stop通道读到true的时候,函数返回,由于使用了defer,会调用Ticker的Stop方法,之后从协程返回,主函数调用如下所示:

func main() {
    ch := UserTicker()
    time.Sleep(20 * time.Second)
    ch <- true
    close(ch)
}

输出如下所示

Ticker2…
Ticker2…
Ticker2…
Ticker2…
Ticker2 Stop

可以看到,我们可以正常退出协程了。

两种类型的定时器:ticker和timer。两者有什么区别呢?
  • ticker只要定义完成,从此刻开始计时,不需要任何其他的操作,每隔固定时间都会触发
  • 使用timer定时器,超时后需要重置,才能继续触发。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值