context包
Context主要分两种,一种是实现超时控制的cancelCtx,一种是传递值得valueCtx。
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
type cancelCtx struct {
Context
mu sync.Mutex // protects following fields
done chan struct{} // created lazily, closed by first cancel call
children map[canceler]struct{} // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
}
type valueCtx struct {
Context
key, val interface{}
}
package main
import (
"fmt"
)
func main() {
gen := func() <-chan int {
dst := make(chan int)
n := 1
go func() {
for {
n++
dst<-n
}
}()
return dst
}
for n := range gen() {
fmt.Println(n)
if n == 5 {
break
}
}
}
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
}
}
}
package main
import (
"context"
"fmt"
"time"
)
const shortDuration = 1 * time.Millisecond
//const shortDuration = 10 * time.Second
func main() {
d := time.Now().Add(shortDuration)
ctx, cancel := context.WithDeadline(context.Background(), d)
//a,b:=<-ctx.Done(); 若加上这两行,赋值shortDuration=10s,程序会阻塞在此处到10s后,打印出 {} false
//fmt.Println(a,b)
// Even though ctx will be expired, it is good practice to call its
// cancellation function in any case. Failure to do so may keep the
// context and its parent alive longer than necessary.
defer cancel()
select {//由于没有默认路径,select被阻塞,在1ms之后,ctx.Done()有数据送达,打印err。
case <-time.After(1 * time.Second)://
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
}
package main
import (
"context"
"fmt"
)
func main() {
type favContextKey string//WithValue的第二个参数必须不是内建类型(如int string等),且必须可比较(不能是),故此处定义一个新类型。
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")
k1 := favContextKey("language1")
ctx := context.WithValue(context.Background(), k, "Go")
ctx1 := context.WithValue(ctx,k1,"GO GO GO")
f(ctx, k)
f(ctx1,k1)
//ctx1.Context是无法调用到ctx的,因为这个valueCtx是不对外暴露的。
f(ctx1,k)//valueCtx实现了Value方法,用以在context链路上获取key对应的值,如果当前context上不存在需要的key,会沿着context链向上寻找key对应的值,直到根节点。
//ctx2 := context.WithValue(ctx1,k,"GO GO GO GO GO ")
//f(ctx2,k)//若引入这两行,打印出的值为GO GO GO GO GO,说明Value方法从最外层开始获取key,取到即返回。
f(ctx, favContextKey("color"))
//ctx2.Context是无法调用到
输出是
found value: Go
found value: GO GO GO
found value: Go
key not found: color