大家好,我是煎鱼。
前几天在公众号分享了一篇 Go timer 源码解析的文章《难以驾驭的 Go timer,一文带你参透计时器的奥秘》。
如果大家也有兴趣共同交流,欢迎关注煎鱼的公众号,加我微信后拉你进群。
在评论区有小伙伴提到了经典的 timer.After
泄露问题,希望我能聊聊,这是一个不能不知的一个大 “坑”。
今天煎鱼就带大家来研讨一下这个问题。
今天是男主角是Go 标准库 time 所提供的 After
方法。函数签名如下:
func After(d Duration) <-chan Time
该方法可以在一定时间(根据所传入的 Duration)后主动返回 time.Time
类型的 channel 消息。
在常见的场景下,我们会基于此方法做一些计时器相关的功能开发,例子如下:
func main() {
ch := make(chan string)
go func() {
time.Sleep(time.Second * 3)
ch <- "脑子进煎鱼了"
}()
select {
case _ = <-ch:
case <-time.After(time.Second * 1):
fmt.Println("煎鱼出去了,超时了!!!")
}
}
在运行 1 秒钟后,输出结果:
煎鱼出去了,超时了!!!
上述程序在在运行 1 秒钟后将触发 time.After
方法的定时消息返回,输出了超时的结果。
从例子来看似乎非常正常,也没什么 “坑” 的样子。难道是 timer.After
方法的虚晃一?
我们再看一个不像是有问题例子,这在 Go 工程中经常能看见,只是大家都没怎么关注。
代码如下:
func main() {
ch := make(chan int, 10)
go func() {
in := 1
for {
in++
ch <- in
}
}()
for {
select {
case _ = <-ch:
// do something...
continue
case <-time.After(3 * time.Minute):
fmt.Printf("现在是:%d,我脑子进煎鱼了!", time.Now().Unix())
}
}
}
在上述代码中,我们构造了一个 for+select+channel
的一个经典的处理模式。
同时在 select+case
中调用了 time.After
方法做超时控制,避免在 channel
等待时阻塞过久,引发其他问题。
看上去都没什么问题,但是细心一看。在运行了一段时间后,粗暴的利用 top
命令一看:
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- azee.cn 版权所有 赣ICP备2024042794号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务