Golang Context包
什么是 Context
Context 是一个 Go 语言标准库,用于在 Goroutine 之间传递上下文信息。在 Goroutine 中使用 Context 可以有效地控制请求的生命周期,防止 Goroutine 泄漏和资源浪费。
Context 可以看作是一个场景,包含了请求的所有信息,如请求和响应,以及一些相关的元数据,如请求的超时时间、请求截止时间等。Context 的设计是基于树型结构的,每个 Context 都有一个父 Context 和零个或多个子 Context。当一个 Context 被取消或过期时,它的所有子 Context 都会被取消。这种机制可以保证 Goroutine 不会泄漏,也不会浪费资源。
Context 中包含了以下信息:
- 取消信号:用于通知 Goroutine 需要取消任务。
- 截止时间:用于控制任务的超时时间。
- 其他元数据:用于传递请求相关的元数据,如请求 ID、用户信息等。
Context 的使用
创建 Context
可以使用 context.Background()
函数创建一个空的 Context,它没有父 Context、没有取消信号和截止时间。一般情况下,我们会在主函数中创建 Context,并将其传递给调用的函数。
func main() {
ctx := context.Background()
doSomething(ctx)
}
取消 Context
通过调用 context.WithCancel(parent)
函数可以创建一个新的 Context,并返回一个取消函数。当调用取消函数时,这个 Context 及其子 Context 都会被取消。
func doSomething(ctx context.Context) {
ctx, cancel := context.WithCancel(ctx)
go func() {
time.Sleep(time.Second)
cancel()
}()
select {
case <-ctx.Done():
fmt.Println("Context canceled")
}
}
上面的代码中,调用 context.WithCancel(parent)
函数创建了一个新的 Context,并返回了一个取消函数 cancel
。在 Goroutine 中,等待 1 秒后调用 cancel()
函数取消 Context。在主函数中,调用 doSomething(ctx)
函数,传递了一个 Context。在 doSomething
函数中,等待 Context 取消信号,并在取消时打印出提示信息。
设置截止时间
通过调用 context.WithTimeout(parent, timeout)
函数可以创建一个新的 Context,并指定一个截止时间。当超过这个时间时,这个 Context 及其子 Context 都会被取消。
func doSomething(ctx context.Context) {
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
select {
case <-ctx.Done():
fmt.Println("Context canceled")
}
}
上面的代码中,调用 context.WithTimeout(parent, timeout)
函数创建了一个新的 Context,并指定了一个 1 秒的截止时间。在 Goroutine 中,等待 Context 取消信号,并在取消时打印出提示信息。
传递元数据
Context 还可以用于传递请求相关的元数据,如请求 ID、用户信息等。通过调用 context.WithValue(parent, key, value)
函数可以创建一个新的 Context,并将指定的键值对存储在其中。
type key int
const (
requestIDKey key = iota
userIDKey
)
func doSomething(ctx context.Context) {
requestID := 123
userID := 456
ctx = context.WithValue(ctx, requestIDKey, requestID)
ctx = context.WithValue(ctx, userIDKey, userID)
// ...
}
func main() {
ctx := context.Background()
doSomething(ctx)
requestID := ctx.Value(requestIDKey).(int)
userID := ctx.Value(userIDKey).(int)
fmt.Println(requestID, userID)
}
上面的代码中,定义了两个键值对,分别对应请求 ID 和用户 ID。在 doSomething
函数中,调用了 context.WithValue(parent, key, value)
函数创建了一个新的 Context,并将请求 ID 和用户 ID 存储在其中。在主函数中,调用了 doSomething(ctx)
函数,并从 Context 中读取了请求 ID 和用户 ID。
总结
Context 是 Go 语言中的一个重要特性,用于在 Goroutine 之间传递上下文信息。Context 可以有效地控制请求的生命周期,防止 Goroutine 泄漏和资源浪费。Context 的使用非常简单,可以通过创建、取消、设置截止时间和传递元数据等方式实现。在实际使用中,需要根据具体的场景选择合适的使用方式。