type cancelCtx struct { Context done chanstruct{} // closed by the first cancel call. mu sync.Mutex children map[canceler]bool// set to nil by the first cancel call err error// 当其被cancel时将会把err设置为非nil }
// 模拟一个最小执行时间的阻塞函数 funcinc(a int)int { res := a + 1// 虽然我只做了一次简单的 +1 的运算, time.Sleep(1 * time.Second) // 但是由于我的机器指令集中没有这条指令, // 所以在我执行了 1000000000 条机器指令, 续了 1s 之后, 我才终于得到结果。B) return res }
// 向外部提供的阻塞接口 // 计算 a + b, 注意 a, b 均不能为负 // 如果计算被中断, 则返回 -1 funcAdd(ctx context.Context, a, b int)int { res := 0 for i := 0; i < a; i++ { res = inc(res) select { case <-ctx.Done(): return-1 default: } } for i := 0; i < b; i++ { res = inc(res) select { case <-ctx.Done(): return-1 default: } } return res }
funcmain() { { // 使用开放的 API 计算 a+b a := 1 b := 2 timeout := 2 * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) res := Add(ctx, 1, 2) fmt.Printf("Compute: %d+%d, result: %d\n", a, b, res) } { // 手动取消 a := 1 b := 2 ctx, cancel := context.WithCancel(context.Background()) gofunc() { time.Sleep(2 * time.Second) cancel() // 在调用处主动取消 }() res := Add(ctx, 1, 2) fmt.Printf("Compute: %d+%d, result: %d\n", a, b, res) } }
funcmain() { // 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) <-chanint { dst := make(chanint) n := 1 gofunc() { 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 } } }
// Even though ctx will be expired, it is good practice to call its // cancelation function in any case. Failure to do so may keep the // context and its parent alive longer than necessary. defer cancel()
select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) }
funcmain() { // Pass a context with a timeout to tell a blocking function that it // should abandon its work after the timeout elapses. ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel()
select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) // prints "context deadline exceeded" }
}
func WithValue(parent Context, key, val interface{}) Context
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") ctx := context.WithValue(context.Background(), k, "Go")