这是我参与「第五届青训营 」笔记创作活动的第14天。
最近各大厂陆续开始收暑期实习的简历了,作为Go语言选手自然要好好学习一下Go语言相关知识。
context,中文译作“上下文”,主要用于在各个goroutine之间传递信息。比如说最长执行时间限制,需要在goroutine之间传递的变量,和在外部函数里杀死goroutine的方法。
其实在我之前用gin和hertz框架写后端的时候,就已经接触到context了。由于它们的中间件和处理函数层层嵌套,之前的中间件,比如jwt认证的中间件,从token中解析出来的用户id等信息,就可以放在context中,便于之后的处理函数获取。同样也可以使用context限制一个请求的最长执行时间,防止长时间占用资源。
用context限时,或是从外部取消可以用context.WithTimeout函数。这个是设置倒计时,如果要执行到某一时刻停止,可以用context.WithDeadline函数。如果只需要从外部取消可以用context.WithCancel函数。
下面是一个“击鼓传花”的例子。调用的goroutine首先会检查运行到自己是否超时了,如果不超时就等一秒然后起一个新的goroutine,否则就退出。
用context让goroutine退出的方法是配合select。ctx.Done()是一个通道,当收到退出信号(超时或是调用了cancel()函数)后,里边便会有数据。如果select从里取出数据,那么就可以退出了。
var wg sync.WaitGroup
func pass(ctx context.Context) {
select {
case <-ctx.Done():
fmt.Println("goroutine exit.")
break
default:
time.Sleep(time.Second)
fmt.Println("running 1s...")
wg.Add(1)
go pass(ctx)
}
wg.Done()
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
wg.Add(1)
go pass(ctx)
wg.Wait()
cancel()
fmt.Println("main exit.")
}
运行结果是:
running 1s...
running 1s...
running 1s...
running 1s...
running 1s...
goroutine exit.
main exit.
程序在设定的5秒后退出了(所以之后调用cancel函数并没有作用)。
想要通过context传值的话,可以使用context.WithValue赋值,在goroutine中用ctx.Value获取。
func pass(ctx context.Context) {
fmt.Println(ctx.Value("uid"))
wg.Done()
}
func main() {
ctx := context.WithValue(context.Background(), "uid", "233")
wg.Add(1)
go pass(ctx)
wg.Wait()
}