Golang教程

Context包

Preview
  • Golang Context包
  • 什么是 Context
  • Context 的使用
  • 创建 Context
  • 取消 Context
  • 设置截止时间
  • 传递元数据
  • 总结

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 的使用非常简单,可以通过创建、取消、设置截止时间和传递元数据等方式实现。在实际使用中,需要根据具体的场景选择合适的使用方式。