type Context

  1. type Context interface {
  2. //Done方法返回一个channel,当Context取消或到达截至时间时,该channel即会关闭
  3. Done() <-chan struct{}
  4. //Err方法返回取消的错误原因,因为什么Context被取消。
  5. Err() error
  6. //Deadline方法是获取设置的截止时间的意思
  7. //第一个返回式是截止时间,到了这个时间点,Context会自动发起取消请求;
  8. //第二个返回值ok==false时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。
  9. Deadline() (deadline time.Time, ok bool)
  10. //Value方法获取该Context上绑定的值
  11. //一个键值对,所以要通过一个Key才可以获取对应的值,这个值是线程安全的
  12. Value(key interface{}) interface{}
  13. }

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

  1. 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))
  2. - 设置超时时间,绝对时间
  3. 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))
  4. - 设置超时时间,相对时间
  5. 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)
  6. - 传值,注意类型是空接口,在使用时要断言
  7. - 作用:设置共享参数,跟踪子系统的执行情况
  8. - 提供的键必须具有可比性,并且不应该是字符串类型或任何其他内置类型,以避免使用上下文的包之间的冲突。
  9. - WithValue的用户应该为键定义自己的类型。
  10. - 为了避免在为接口{}赋值时进行分配,上下文键通常有具体的类型结构体{}。或者,导出的上下文关键变量的静态类型应该是point
  11. ```go
  12. package main
  13. import (
  14. "context"
  15. "fmt"
  16. "math/rand"
  17. "time"
  18. )
  19. const(
  20. Elapsed ="elapsed"
  21. )
  22. func MyHandle() {
  23. ctx:=context.WithValue(context.Background(),Elapsed,time.Now())
  24. rand.Seed(time.Now().UnixNano())
  25. a(ctx)
  26. }
  27. func a(ctx context.Context){
  28. time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)
  29. elapsed := time.Since(ctx.Value(Elapsed).(time.Time))
  30. fmt.Printf("traceid:%v,func:%v\n",elapsed,"a")
  31. b(ctx)
  32. }
  33. func b(ctx context.Context){
  34. time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)
  35. elapsed := time.Since(ctx.Value(Elapsed).(time.Time))
  36. fmt.Printf("traceid:%v,func:%v\n",elapsed,"b")
  37. c(ctx)
  38. }
  39. func c(ctx context.Context){
  40. time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)
  41. elapsed := time.Since(ctx.Value(Elapsed).(time.Time))
  42. fmt.Printf("traceid:%v,func:%v\n",elapsed,"c")
  43. }
  44. func main() {
  45. MyHandle()
  46. }
  47. traceid:1.0005927s,func:a
  48. traceid:3.0009336s,func:b
  49. traceid:4.0012555s,func:c

cancel方法源码

不必担心cancel多次被调用的问题,他的内部已经做了判断

  1. func (c *cancelCtx) cancel(removeFromParent bool, err error) {
  2. if err == nil {
  3. panic("context: internal error: missing cancel error")
  4. }
  5. c.mu.Lock()
  6. if c.err != nil {
  7. c.mu.Unlock()
  8. return // already canceled
  9. }
  10. c.err = err
  11. if c.done == nil {
  12. c.done = closedchan
  13. } else {
  14. close(c.done)
  15. }
  16. for child := range c.children {
  17. // NOTE: acquiring the child's lock while holding parent's lock.
  18. child.cancel(false, err)
  19. }
  20. c.children = nil
  21. c.mu.Unlock()
  22. if removeFromParent {
  23. removeChild(c.Context, c)
  24. }
  25. }

例子一:按设置的时间自动关闭

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "os"
  6. "time"
  7. )
  8. var Logg *log.Logger
  9. var StatusChan = make(chan int)
  10. func MyHandle() {
  11. ctx,_:=context.WithDeadline(context.Background(),time.Now().Add(time.Second*5))
  12. //ctx,_:=context.WithTimeout(context.Background(),time.Second*5)
  13. go Do(ctx)
  14. }
  15. func Do(ctx context.Context){
  16. for {
  17. time.Sleep(time.Second)
  18. select {
  19. case <- ctx.Done():
  20. Logg.Printf("done")
  21. StatusChan<-1
  22. default:
  23. Logg.Printf("work")
  24. }
  25. }
  26. }
  27. func main() {
  28. Logg =log.New(os.Stdout,"",log.Ltime)
  29. MyHandle()
  30. <- StatusChan
  31. Logg.Printf("down")
  32. }
  33. 13:45:41 work
  34. 13:45:42 work
  35. 13:45:43 work
  36. 13:45:44 work
  37. 13:45:45 done
  38. 13:45:45 down

例子二:在设置的时间前,主动关闭

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "os"
  6. "time"
  7. )
  8. var Logg *log.Logger
  9. func MyHandle() {
  10. ctx,cancel:=context.WithDeadline(context.Background(),time.Now().Add(time.Second*5))
  11. //ctx,_:=context.WithTimeout(context.Background(),time.Second*5)
  12. go Do(ctx)
  13. select {
  14. case <-time.After(time.Second*3):
  15. cancel()
  16. }
  17. }
  18. func Do(ctx context.Context){
  19. for {
  20. time.Sleep(time.Second)
  21. select {
  22. case <- ctx.Done():
  23. Logg.Printf("done")
  24. default:
  25. Logg.Printf("work")
  26. }
  27. }
  28. }
  29. func main() {
  30. Logg =log.New(os.Stdout,"",log.Ltime)
  31. MyHandle()
  32. Logg.Printf("down")
  33. }
  34. 13:44:09 work
  35. 13:44:10 work
  36. 13:44:11 down