context简介
因为context
具有在多个不同goroutine
中传递上下文信息的性质,所以其常用于并发控制。
下面是对context
包的详细使用:
context的使用
创建一个context
context
包提供了两种创建方式:
context.Background()
context.TODO()
这两种方式创建出来的是根context
,不具有任何功能。需要根据实际选择context
包提供的With
系列函数来解决相应的问题。
下面是context
包提供的With
系列函数:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
context
的衍生具有树形结构的特点。
下面是对这些With
函数的具体使用介绍:
With系列函数
WithCancel 取消控制
WithCancel
的作用是,我们可以通过传递这样的上下文,去控制多个goroutine
,通过cancel
函数,在任意时刻让这些goroutine
取消。
下面是例子:
func main() {
ctx, cancel := context.WithCancel(context.Background())
go task(ctx)
time.Sleep(5 * time.Second)
cancel()
time.Sleep(time.Second)
}
func task(ctx context.Context) {
for range time.Tick(time.Second) {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
fmt.Println("tasking...")
}
}
}
超时控制
一个健壮的程序都是需要设置超时时间的,避免由于服务端长时间响应而消耗资源。所以,一些web
框架都会采用WithDeadline
和WithTimeOut
函数来做超时控制。
下面是例子:
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go task(ctx)
time.Sleep(6 * time.Second)
}
func task(ctx context.Context) {
for range time.Tick(time.Second) {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
fmt.Println("tasking...")
}
}
}
WithValue 携带数据
WithValue
函数可以返回一个可携带数据的context
,可以用于在多个goroutine
进行传递。
例如,在日常业务开发中,需要有一个trace_id
来串联所有日志,那么就可以使用WithValue
来实现。
下面是例子:
func main() {
ctx := context.WithValue(context.Background(), "key", "value")
go task(ctx)
time.Sleep(time.Second)
}
func task(ctx context.Context) {
fmt.Println(ctx.Value("key"))
}
使用WithVlue
的注意事项:
总结
context
包在做并发控制上具有相当方便的功能,如在做任务的取消、超时以及传递隐式参数的情境。