一个人说起自己时,便会得意忘形。——梅里美《卡门》
更好的阅读体验请移步到微信公众号: golang超时不控制,那你还配是gopher?
1. 前言
为什么超时需要控制,这个大家知道吗?自己在脑瓜子里面回想下曾经写过的代码超时控制怎么实现的。那么今天就给大家带来一篇超时控制实战篇,助你在项目中得心应手,废话不多说,直接上干货。
2. 为什么超时需要控制
- 请求时间过长,用户侧可能已经离开本页面了,服务端还在消耗资源处理,得到的结果没有意义。
- 过长时间的服务端处理会占用过多资源,导致并发能力下降,甚至出现不可用事故。
golang中一般一个请求是由多个串行或并行的子任务来完成的,每个子任务可能是另外的内部请求,那么当这个请求超时的时候,我们就需要快速返回,释放占用的资源,比如goroutine,文件描述符等。
3. 平民版逻辑
func Do(job interface{}) error {
//模拟超时任务或者请求
time.Sleep(time.Minute)
return nil
}
func requestDo(ctx context.Context, job interface{}) error {
return Do(job)
}
这样的实现可能用户无法忍受,因为一旦调用Do发生超时,用户侧就会等待很长一段时间没有响应,进而用户带着抱怨离开了页面,真是难过啊。
4. 精英版逻辑
func requestDo(ctx context.Context, job interface{}) error {
ctx, cancel := context.WithTimeout(ctx, time.Second*2)
defer cancel()
done := make(chan error)
go func() {
//在这里调用超时控制请求或者任务
done <- Do(job)
}()
select {
case err := <-done: //请求返回
return err
case <-ctx.Done(): //超时控制
return ctx.Err()
}
}
大家发现问题了吗,亲爱的伙伴们,带着你们的慧眼,识别代码的bug,来来来。
好,那我给大家说下哪里有问题:
如果超时被控制返回了 即命中case <-ctx.Done(),那么直接就结束当前requestDo协称,但是我们的Do协称还在继续执行呢,当它准备返回的时候发现done没有goroutine接受了,那么Do协称就会一直卡在那里,导致协称泄漏啊
5. 超人版逻辑
解决上面bug的方案之一就是给done初始化一个size大小的空间。
done := make(chan error, 1)
这样的话,Do协称超时返回了,自动把结果写入done中,然后Do协称会自动退出,这样协称就不会泄漏了。
那有人会问,写进去之后会不会有影响啊,毕竟done没有人去接受了,那么这里明确告诉大家没有影响的,chan毕竟是一个对象,golang的channel资源是可以自动GC掉的。
6. 如果Do发生panic了呢
如果Do发生panic,此时就会发现panic是无法被捕获的,原因是因为在 requestDo内部起的goroutine里产生的panic其它goroutine无法捕获。
解决办法就是: requestDo里加上panicChan来处理,同样,需要 panicChan的buffer size为1,如下
panicChan := make(chan interface{}, 1)
详细请看:
func requestDo(ctx context.Context, job interface{}) error {
ctx, cancel := context.WithTimeout(ctx, time.Second*2)
defer cancel()
done := make(chan error)
panicChan := make(chan interface{}, 1)
go func() {
defer func() {
if p := recover(); p != nil {
panicChan <- p
}
}()
done <- Do(job)
}()
select {
case err := <-done:
return err
case p := <-panicChan:
panic(p) //这里也需要panic
case <-ctx.Done():
return ctx.Err()
}
}
改完就可以在requestDo的调用方处理panic 了。
7. 小结
大家看到了吧,通过以上知识点的学习,我相信大家可以写出更加健全的超时控制逻辑了,那还在等什么,快快实践吧。
8. 关注公众号
微信公众号:堆栈future
希望大家关注哈,原创不容易,求点赞,求关注,求分享