一起学context(二)——超时控制
2019年1月2日 · 92 字 · 1 分钟
上一篇文章讲到如何使用context来传值,实际上context还有另外一个重要功能——goroutine的超时控制。 很多时候goroutine如果不设超时,一旦发生阻塞将无限等待,协程数会越来越多,导致耗尽服务器内存。
分类
拥有超时控制的context有以下几种:
- context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) 指定时长超时结束
- context.WithCancel(parent Context) (ctx Context, cancel CancelFunc) 手动结束
- context.WithDeadline(parent Context, d time.Time) (Context, CancelFunc) 指定时间结束
一般常用的话就context.WithTimeout
示例代码
所有超时控制结束的代码结构都是类似的,示例代码如下:
package main
import (
"context"
"time"
"fmt"
)
func main() {
ctx, cancel := context.WithTimeout(context.TODO(), time.Second*3)
defer cancel() // 防止任务比超时时间短导致资源未释放
// 启动协程
go task(ctx)
// 主协程需要等待,否则直接退出
time.Sleep(time.Second * 4)
}
func task(ctx context.Context) {
ch := make(chan struct{}, 0)
// 真正的任务协程
go func() {
// 模拟两秒耗时任务
time.Sleep(time.Second * 2)
ch <- struct{}{}
}()
select {
case <-ch:
fmt.Println("done")
case <-ctx.Done():
fmt.Println("timeout")
}
}
task函数是一般情况下ctx的处理代码,很多第三方框架会声明具体函数的第一个参数为context.Context来允许设定代码超时时间。