context 是go的基础包
context 的使用场景:1. 控制关闭goruntine , 防止溢出 2. 定时完成goruntine 3. 带参数给 goruntine
对应的有以下几种 context :
context.WithCancel context.WithDeadline context.WithTimeout context.WithValue
context.Background() 用来 new 一个新 context context.TODO() 用来 new 一个context 备用
类关系:
源码解析:
查看 go 源码或 看 http://www.codebaoku.com/godeep/goddeep-context-src.html
使用参照:
cancel:
gen := func(ctx context.Context) chan int { dst := make(chan int) n := 1 go func() { fmt.Println("new go ") for { select { case <-ctx.Done(): fmt.Println("goroutine over") return // return结束该goroutine,防止泄露 case dst <- n: n++ } } }() return dst } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // 当我们取完需要的整数后调用cancel for n := range gen(ctx) { fmt.Println(n) if n == 5 { break } }
deadline / timeout
d := time.Now().Add(50 * time.Millisecond) ctx, _ := context.WithDeadline(context.Background(), d) // ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) // 尽管ctx会过期,但在任何情况下调用它的cancel函数都是很好的实践。 // 如果不这样做,可能会使上下文及其父类存活的时间超过必要的时间。 // defer cancel() 如果调用, 是主动停止(canceled) goruntine; 如果不调用 则是超时出 deadline exceeded go func() { select { case <-time.After(1 * time.Second): fmt.Println("sleep ") case <-ctx.Done(): fmt.Println(ctx.Err()) fmt.Println("over") return } }() time.Sleep(time.Second * 5)
contextval
type favContextKey string // 定义一个key类型 // f:一个从上下文中根据key取value的函数 f := func(ctx context.Context, k favContextKey) { if v := ctx.Value(k); v != nil { fmt.Println("found value:", v) return } fmt.Println("key not found:", k) } k := favContextKey("language") // 创建一个携带key为k,value为"Go"的上下文 // context.TODO() ctx := context.WithValue(context.Background(), k, "Go") f(ctx, k) f(ctx, favContextKey("color"))