go基础第九篇:context

1、带取消的context

context.WithCancel(parent Context) (ctx Context, cancel CancelFunc)

传入一个父context,返回一个可以手动取消的子context及其取消函数。

我们可以手动调用cancel()函数来取消子context,当cancel()被调用后,或者父context被取消后,子context的Done channel会close,通过<-ctx.Done()方式监听子context的所有goroutine都会收到通知。cancel一个context会释放关联的资源,所以context应该尽快cancel,如果不需要手动cancel的话,要用defer cancel()。

常见用法:主协程调用WithCancel方法,生成一个子context及取消函数。在子协程中使用for循环,用select多路选择从子context的Done方法返回的channel中取数据。在主协程中调用取消函数,当子协程从子context的Done方法返回的channel中取到数据后,就退出子协程。

 

2、带超时的context

context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunction)

context.WithDeadline(parent Context, timeout time.time) (Context, CancelFunction)

传入一个父context和一个时间,返回一个到点自动取消的子context及其取消函数。

func main() {
    ctx, cancelF := context.WithTimeout(context.Background(), time.Second*3)
    defer func() {
        fmt.Println("context cancel")
        cancelF()
    }()
    go task(ctx)
    time.Sleep(time.Second * 10)
}

func doSomething(ch chan int) {
    time.Sleep(time.Second * 2)
    ch <- 0
}

func task(ctx context.Context) {
    ch := make(chan int, 0)
    go doSomething(ch)
    select {
    case a := <-ch:
        fmt.Println("a=", a)
    case b := <-ctx.Done():
        fmt.Println("超时", b)
    }
}

 

3、带值的context

context.WithValue(parent Context, key, val interface{}) Context

传入一个父context和一个键值对,返回一个子context。可以在子协程中调用子context的Value()方法根据键获取值。

func main() {
    ctx := context.WithValue(context.Background(), "requestId", "7a9f3b87-2efe-4a58-9be0-d1a5a8a488f1")
    go task(ctx)
    time.Sleep(time.Second * 3)
}

func task(ctx context.Context) {
    requestId := ctx.Value("requestId")
    fmt.Println(requestId)
    fmt.Println(reflect.TypeOf(requestId))
}

 

posted on 2021-03-11 11:01  koushr  阅读(73)  评论(0编辑  收藏  举报

导航