context
主要用来在 goroutine
之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等
context接口
1 2 3 4 5 6
| type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} }
|
Deadline
方法的第一个返回值表示还有多久到期,第二个返回值 表示是否到期
Done
方法返回一个通道,可以监听该通道的信号,如果收到信号则表示通道已经关闭,需要执行退出
Err
方法会返回退出的原因
value
方法返回指定key对应的value,这是context携带的值
默认的上下文
context包中最常用的方法还是context.Background
、context.TODO
,这两个方法都会返回预先初始化好的私有变量background
和todo
go/src/context/context.go)
1 2 3 4 5 6 7 8 9 10 11 12
| var ( background = new(emptyCtx) todo = new(emptyCtx) )
func Background() Context { return background }
func TODO() Context { return todo }
|
这两个私有变量都是通过new(emptyCtx)
语句初始化的,它们是指向私有结构体context.emptyCtx
的指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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" }
|
emptyCtx什么内容都没有,其不可以被退出,也不能携带值。
context.Background
是上下文的默认值,所有其他的上下文都应该从它衍生出来,如果当前函数没有上下文作为入参,我们都会使用 context.Background 作为起始的上下文向下传递
context.TODO
应该仅在不确定应该使用哪种上下文时使用
WithCancel
context.WithCancel
函数能够从 context.Context
中衍生出一个新的子上下文并返回用于取消该上下文的函数。一旦我们执行返回的取消函数,当前上下文以及它的子上下文都会被取消,所有的 Goroutine
都会同步收到这一取消信号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| func main() { ctx, cancelFunc := context.WithCancel(context.Background()) go Op(ctx) time.Sleep(time.Second * 3) cancelFunc() time.Sleep(time.Second) fmt.Println("main stop") }
func Op(ctx context.Context) { for { select { default: time.Sleep(time.Second) fmt.Println("Op run") case <-ctx.Done(): fmt.Println("parent stop") return } } }
|
WithTimeout
context.WithTimeout
函数接收父上下文(parent
)和一个超时时间,能够从 context.Context
中衍生出一个新的子上下文并返回用于取消该上下文的函数。执行取消函数时功能和WithCancel
一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| func main() { ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*3) defer cancelFunc() go Op(ctx) <-ctx.Done() time.Sleep(time.Second) fmt.Println("main stop") }
func Op(ctx context.Context) { for { select { default: time.Sleep(time.Second) fmt.Println("Op run") case <-ctx.Done(): fmt.Println("parent stop") return } } }
|
WithDeadline
context.WithDeadline
函数接收父上下文(parent
)和一个截止时间,能够从 context.Context
中衍生出一个新的子上下文并返回用于取消该上下文的函数。执行取消函数时功能和WithCancel
一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| func main() { ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(time.Second*5)) defer cancelFunc() go Op(ctx) <-ctx.Done() time.Sleep(time.Second) fmt.Println("main stop") }
func Op(ctx context.Context) { for { select { default: time.Sleep(time.Second) fmt.Println("Op run") case <-ctx.Done(): fmt.Println("parent stop") return } } }
|
WithValue
context.WithValue
能从父 Context
中创建一个子子 Context
,并传体一个键值对信息给子 Context
,在子 Context
中,通过context.Value
获取对应的值信息。
1 2 3 4 5 6 7 8
| func main() { valueCtx := context.WithValue(context.Background(), "name", "hanpy") go func(ctx context.Context) { fmt.Printf("取出上下文中的name: %v\n",ctx.Value("name")) }(valueCtx) time.Sleep(time.Second) fmt.Println("main stop") }
|