Golang中的Context
当我们学习golang时,总会看见context这个词(比如gin.Context),但是总感觉context好像没什么用,那context有什么用?该怎么用?
go语言Context的定义
在 Go 语言中,context 是一种用于跨 API 和进程传递取消信号、超时和截止时间的机制。它可以用来管理一个请求的上下文信息,并在需要的时候进行取消操作,以便释放资源或终止操作。context 包提供了一个 Context 类型以及一些相关的函数,用于创建、传递和取消上下文。
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}//返回一个只读管道
Err() error //当执行Done时,记录为什么关闭
Value(key any) any //用于传入Key-Value和通过Key取出Value
}
创建一个空的context
golang提供了两个方法来创建一个Context,Todo和Background,他们都返回一个空的Context,作为我们最开始的Context来进行传递。
context := context.Background()
用法一: 传递Key-Value
在函数执行过程中,我们可以通过context在函数调用过程中的传递,来设置或者获取Key-Value。
示例代码
func step1(ctx context.Context) context.Context {
child := context.WithValue(ctx, "name", "小白")
return child
}
func step2(ctx context.Context) context.Context {
child := context.WithValue(ctx, "age", "18")
return child
}
func step3(ctx context.Context) {
fmt.Printf("name %s age %s",ctx.Value("name"),ctx.Value("age"))
}
func main() {
//实现一个空Context,最开始的context
grandpa := context.Background()
father := step1(grandpa)
grandson := step2(father)
step3(grandson)
}
这段代码的输出结果为name 小白 age 18, 成功的从context中获取到了传递的值。
用法二: 截止时间和超时
可以在 Context 中设置截止时间,一旦超过指定的时间,Context 会自动取消。这对于避免某些操作无限期地等待非常有用。
示例代码
func f1() {
ctx,cancel := context.WithTimeout(context.TODO(),time.Millisecond * 100)
defer cancel()
select {
case <-ctx.Done():
err := ctx.Err().Error()
println(err)
}
}
func main() {
f1()
}
在上面的代码中我们创建了一个超时时间为100ms的context,当超时,会自动调用Done函数,我们通过select捕获,并打印出调用原因。
这段代码的输出为context deadline exceeded,
注意,调用Done函数取决于context调用过程中寿命最短的那个。
用法三: 取消操作
当一个操作需要在某个条件满足或者超过一定时间后终止时,context 可以通过传递取消信号来实现。这对于在超时、用户请求取消或错误发生时,能够及时中止操作并释放资源非常有用。
示例代码
func f2() {
ctx,cancel := context.WithCancel(context.TODO())
start := time.Now()
go func() {
time.Sleep(time.Millisecond * 100)
cancel()
}()
select {
case <- ctx.Done():
end := time.Now()
fmt.Println(end.Sub(start).Milliseconds())
err := ctx.Err().Error()
println(err)
}
}
func main() {
f2()
}
在这段代码中,我们创建了一个取消操作的context,当我们主动执行cancel函数时,会触发Done函数,停止context。这段代码的输出为112 context canceled