type Context
type Context interface {//Done方法返回一个channel,当Context取消或到达截至时间时,该channel即会关闭Done() <-chan struct{}//Err方法返回取消的错误原因,因为什么Context被取消。Err() error//Deadline方法是获取设置的截止时间的意思//第一个返回式是截止时间,到了这个时间点,Context会自动发起取消请求;//第二个返回值ok==false时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。Deadline() (deadline time.Time, ok bool)//Value方法获取该Context上绑定的值//一个键值对,所以要通过一个Key才可以获取对应的值,这个值是线程安全的Value(key interface{}) interface{}}
func TODO() Context
- TODO返回一个非nil的空上下文。代码应该使用上下文。当不清楚要使用哪个上下文或它还不可用时(因为周围的函数还没有扩展到接受上下文参数),TODO。TODO由静态分析工具识别,该工具确定上下文是否在程序中正确传播。
func Background() Context
- 返回一个非nil的空上下文。它从未被取消,没有值,也没有截止日期。它通常由主函数、初始化和测试使用,并作为传入请求的顶级上下文
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
- 返回带有新Done通道的父进程的副本。当调用返回的cancel函数或当关闭父上下文的Done通道时,将关闭返回上下文的Done通道,无论先发生什么情况。 ```go package main
import ( “context” “log” “os” “time” )
var Logg *log.Logger
func MyHandle() { ctx,cancel:=context.WithCancel(context.Background()) go Do(ctx) time.Sleep(time.Second*10) cancel() } func Do(ctx context.Context){ for { time.Sleep(time.Second) select { case <- ctx.Done(): Logg.Printf(“done”) return default: Logg.Printf(“work”) } } } func main() { Logg =log.New(os.Stdout,””,log.Ltime) MyHandle() Logg.Printf(“down”) } 13:15:13 work 13:15:14 work 13:15:15 work 13:15:16 work 13:15:17 work 13:15:18 work 13:15:19 work 13:15:20 work 13:15:21 work 13:15:22 down
func WithDeadline(parent [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), deadline [time](https://studygolang.com/time).[Time](https://studygolang.com/time#Time)) ([Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), [CancelFunc](https://studygolang.com/static/pkgdoc/pkg/context.htm#CancelFunc))- 设置超时时间,绝对时间func WithTimeout(parent [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), timeout [time](https://studygolang.com/time).[Duration](https://studygolang.com/time#Duration)) ([Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), [CancelFunc](https://studygolang.com/static/pkgdoc/pkg/context.htm#CancelFunc))- 设置超时时间,相对时间func WithValue(parent [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), key, val interface{}) [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context)- 传值,注意类型是空接口,在使用时要断言- 作用:设置共享参数,跟踪子系统的执行情况- 提供的键必须具有可比性,并且不应该是字符串类型或任何其他内置类型,以避免使用上下文的包之间的冲突。- WithValue的用户应该为键定义自己的类型。- 为了避免在为接口{}赋值时进行分配,上下文键通常有具体的类型结构体{}。或者,导出的上下文关键变量的静态类型应该是point```gopackage mainimport ("context""fmt""math/rand""time")const(Elapsed ="elapsed")func MyHandle() {ctx:=context.WithValue(context.Background(),Elapsed,time.Now())rand.Seed(time.Now().UnixNano())a(ctx)}func a(ctx context.Context){time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)elapsed := time.Since(ctx.Value(Elapsed).(time.Time))fmt.Printf("traceid:%v,func:%v\n",elapsed,"a")b(ctx)}func b(ctx context.Context){time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)elapsed := time.Since(ctx.Value(Elapsed).(time.Time))fmt.Printf("traceid:%v,func:%v\n",elapsed,"b")c(ctx)}func c(ctx context.Context){time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)elapsed := time.Since(ctx.Value(Elapsed).(time.Time))fmt.Printf("traceid:%v,func:%v\n",elapsed,"c")}func main() {MyHandle()}traceid:1.0005927s,func:atraceid:3.0009336s,func:btraceid:4.0012555s,func:c
cancel方法源码
不必担心cancel多次被调用的问题,他的内部已经做了判断
func (c *cancelCtx) cancel(removeFromParent bool, err error) {if err == nil {panic("context: internal error: missing cancel error")}c.mu.Lock()if c.err != nil {c.mu.Unlock()return // already canceled}c.err = errif c.done == nil {c.done = closedchan} else {close(c.done)}for child := range c.children {// NOTE: acquiring the child's lock while holding parent's lock.child.cancel(false, err)}c.children = nilc.mu.Unlock()if removeFromParent {removeChild(c.Context, c)}}
例子一:按设置的时间自动关闭
package mainimport ("context""log""os""time")var Logg *log.Loggervar StatusChan = make(chan int)func MyHandle() {ctx,_:=context.WithDeadline(context.Background(),time.Now().Add(time.Second*5))//ctx,_:=context.WithTimeout(context.Background(),time.Second*5)go Do(ctx)}func Do(ctx context.Context){for {time.Sleep(time.Second)select {case <- ctx.Done():Logg.Printf("done")StatusChan<-1default:Logg.Printf("work")}}}func main() {Logg =log.New(os.Stdout,"",log.Ltime)MyHandle()<- StatusChanLogg.Printf("down")}13:45:41 work13:45:42 work13:45:43 work13:45:44 work13:45:45 done13:45:45 down
例子二:在设置的时间前,主动关闭
package mainimport ("context""log""os""time")var Logg *log.Loggerfunc MyHandle() {ctx,cancel:=context.WithDeadline(context.Background(),time.Now().Add(time.Second*5))//ctx,_:=context.WithTimeout(context.Background(),time.Second*5)go Do(ctx)select {case <-time.After(time.Second*3):cancel()}}func Do(ctx context.Context){for {time.Sleep(time.Second)select {case <- ctx.Done():Logg.Printf("done")default:Logg.Printf("work")}}}func main() {Logg =log.New(os.Stdout,"",log.Ltime)MyHandle()Logg.Printf("down")}13:44:09 work13:44:10 work13:44:11 down
