01
介绍
在 Go1.7 中,标准库加入了 context 包,context 包定义了一个 Context (上下文)类型,可以在 Api 之间和进程之间传递信息,还提供了超时(timeout)和取消(cancel)机制。
Go 标准库中,database/sql,net,net/http 等包中都使用了 Context。
在 Go 应用开发中,一般用于请求链路中传递上下文信息,控制子 goroutine 等场景中。
02
Context 接口
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
context 包定义了一个 Context 接口,包含 4 个方法:
03
创建 Context
context 包中包含两个生成顶层 Context 的方法:
这两个方法都是返回一个非 nil,空 Context,没有任何值,不会被 cancel,不会超时,没有截止日期。实际上,这两个方法的底层实现是一样的。
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}
这两个方法都是 emptyCtx 的指针类型,是一个不可取消,没有设置截止时间,没有任何值得 Context。
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}
04
CancelFunc 类型
type CancelFunc func()
CancelFunc 用于主动让 goroutine 停止。多个goroutine 可以同时调用 CancelFunc。在第一个调用之后,随后对 CancelFunc 的调用什么也不做。
05
函数
创建了顶层 Context,想要创建子 Context,可以使用以下方法:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
示例代码:
var name string
func main () {
// ctx, cancle := context.WithCancel(context.Background())
// d := time.Now().Add(time.Second * 2)
// ctx, cancle := context.WithDeadline(context.Background(), d)
ctx, cancle := context.WithTimeout(context.Background(), time.Second * 2)
valueCtx := context.WithValue(ctx, name, "lucy")
go work(valueCtx)
time.Sleep(time.Second * 3)
fmt.Println("停止工作。")
cancle()
time.Sleep(time.Second * 5)
}
func work(ctx context.Context) {
for {
select {
case <- ctx.Done():
fmt.Println(ctx.Value(name), "工作结束!")
return
default:
fmt.Println(ctx.Value(name), "工作中。")
time.Sleep(time.Second * 1)
}
}
}
06
规范
07
总结
Context 一般用于控制 goroutine,使用 Context 主动取消 goroutine 的运行。除此之外,关于控制 goroutine,我们还可以使用 WaitGroup 和 channel 被动取消 goroutine。