golang context
用来传递上下文的信息,该类型可跨 API 和进程间传输截止日期、取消信号和其他请求范围值,一般用作函数的第一个参数。
介绍
Context
由一个接口和几个实现组成
Context 接口
参考
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}
初始化方法包括:
# 创建 context
func Background() Context
func TODO() Context // 不确定应该使用哪种上下文时使用
# context 衍生
func WithValue(parent Context, key, val any) Context
func WithoutCancel(parent Context) Context
实现
- AfterFunc(ctx, f)
- Cause(c)
- WithCancel(parent)
- WithCancelCause(parent)
- WithDeadline(parent, d)
- WithDeadlineCause(parent, d, cause)
- WithTimeout(parent, timeout)
- WithTimeoutCause(parent, timeout, cause)
示例
demo1
type contextKey string
const userIDKey contextKey = "userid"
...
ctx := context.WithValue(r.Context(), userIDKey, claimsWithPayload.Id)
...
a := r.Context().Value(userIDKey).(string)
说明:
- 若不定义
contextKey
会报错 should not use built-in type string as key for value; define your own type to avoid collisions (SA1029)
select 配合使用
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
select {
case <-time.After(1 * time.Second):
fmt.Println("Done")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
}
context deadline exceeded
经常与 for + goroutine + select + chan
一起使用
WithCancel
package main
import (
"context"
"fmt"
)
func main() {
// gen generates integers in a separate goroutine and
// sends them to the returned channel.
// The callers of gen need to cancel the context once
// they are done consuming generated integers not to leak
// the internal goroutine started by gen.
gen := func(ctx context.Context) <-chan int {
dst := make(chan int)
n := 1
go func() {
for {
select {
case <-ctx.Done():
return // returning not to leak the goroutine
case dst <- n:
n++
}
}
}()
return dst
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // cancel when we are finished consuming integers
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
break
}
}
}