写点什么

谈谈 Go 的固定时长定时器和周期性时长定时器

用户头像
Regan Yue
关注
发布于: 31 分钟前
谈谈Go的固定时长定时器和周期性时长定时器

谈谈 Go 的固定时长定时器和周期性时长定时器

我们之前要想在调度里面实现延时执行,我们可以使用管道阻塞,直到有人往管道里面写东西才变通畅,还可以使用 sleep 来睡觉,但是睡觉的过程,协程啥也干不了也占用资源。所以我们要用到接下来讲的定时器,不会像 sleep 那样睡的时候也占用资源。


先来看看下面这段代码:


package main
import ( "fmt" "time")
func main() { timer := time.NewTimer(3 * time.Second) fmt.Println("定时器创建完毕!") fmt.Println(time.Now()) //阻塞3秒后才能读出时间 x := <- timer.C //这个C是一个单向的只读管道 fmt.Println(x)}
复制代码


运行结果是这样的:


定时器创建完毕!2021-08-24 14:02:28.6664158 +0800 CST m=+0.0129976012021-08-24 14:02:31.670071 +0800 CST m=+3.016652801
复制代码


我们可以看到,运行结果和我们要达到的目的基本一致,三秒的定时器创建完毕后,阻塞三秒后才能读出时间。


我们来看看这个


x := <- timer.C
复制代码


根据下面这段代码可知,这个 C 是一个单向的只读管道:


type Timer struct {  C <-chan Time  r runtimeTimer}
复制代码


如果要描述一个单向的只写的管道,应该这样写:


C chan <- Time
复制代码


但是如果要达到同样的目的,我们可以使用下面这种更简单的方式:


func main() {  fmt.Println(time.Now())  x := <- time.After(3*time.Second)  fmt.Println(x)}
复制代码


使用time.After()等待规定的一段时间,然后就在返回的管道上发送当前时间。它相当于 NewTimer(d).C。垃圾收集器不会回收底层的 Timer,直到计时器触发才回收。 如果需要考虑效率,请改用 NewTimer 并在不再需要计时器时调用 Timer.Stop来结束。


当然我们也可以使用下面这种方法,两种方法都可以:


x := <- time.NewTimer(3 * time.Second).C
复制代码


刚才固定时长定时器的就是一个定时炸弹设置为三秒钟那三秒钟之后就爆炸,现在我们看看周期性时长定时器吧!


func main() {  ticker := time.NewTicker(1 * time.Second)
var i int for{ x := <- ticker.C fmt.Print("\r",x) i++ if i>3{ //停掉秒表会导致ticker.C永远无法读出数据, //一定要读会导致死锁. ticker.Stop() break } } fmt.Println("计时结束")}
复制代码


这段代码的意思是,设置一个周期性时长定时器,然后每一秒从管道内读一次数据,然后输出直到 i>3,就使用ticker.Stop()将定时器结束,然后停止循环,然后告诉你计时结束。


如果将定时器结束后,你仍然要坚持读,就会出现下面这种情况!


fatal error: all goroutines are asleep - deadlock!


出现死锁!所以这里需要用到 break.

发布于: 31 分钟前阅读数: 6
用户头像

Regan Yue

关注

还未添加个人签名 2020.08.12 加入

还未添加个人简介

评论

发布
暂无评论
谈谈Go的固定时长定时器和周期性时长定时器