取消后是否可以访问 go 上下文值?

围棋中的学习情境。我尝试了上下文取消,它尝试在取消后访问设置为上下文的值。令我惊讶的是,它奏效了:


    import (

    "context"

    "fmt"

    "time"

)


func test(ctx context.Context, cancelFunc context.CancelFunc){

    intervalTicker := time.NewTicker(time.Second * 2).C

    expiryTicker := time.NewTicker(time.Second * 5).C

    for {

        select {

        case <-ctx.Done():

            fmt.Println(ctx.Err())

            return

        case <-intervalTicker:

            fmt.Println("interval")

        case <-expiryTicker:

            fmt.Println("expiry")

            func() {

                defer cancelFunc()

                fmt.Println("Calling context cancel")

            }()

            return

        }

    }

}


func main() {

    type key string

    var contextKey key

    parent := context.WithValue(context.TODO(), contextKey, "V1")

    ctx, cancelFunc := context.WithCancel(parent)

    test(ctx, cancelFunc)


    fmt.Println(ctx.Value(contextKey))

}

当我将相同的子上下文和 cancel 函数传递给测试函数时,我本来希望上下文被取消并且值不可用。难道不是这样吗?


人到中年有点甜
浏览 117回答 1
1回答

白猪掌柜的

从上下文中。WithCancel&nbsp;文档当调用返回的 cancel 函数或父上下文的 Done 通道时(以先发生者为准),返回上下文的 Done 通道将关闭。从上下文中。上下文文档Done 返回一个通道,当代表此上下文完成的工作应被取消时,该通道已关闭。取消上下文不应意味着“销毁此上下文”或“使此上下文不再可用”。这纯粹是向上下文的用户发出信号,表明工作应该被取消。此信号不是魔术,必须明确检查。请考虑以下情况:select {case <-ctx.Done():&nbsp; &nbsp; returndefault:&nbsp; &nbsp; value := ctx.Value("something")&nbsp; &nbsp; doSomething(value)}现在想象一下,上下文按照您的想象工作,在取消时,值不再可检索。这种情况现在可能是可能的:select {case <-ctx.Done():&nbsp; &nbsp; returndefault:&nbsp; &nbsp; // OH NO! Even though we just checked and it was ok,&nbsp; &nbsp; // some other goroutine called cancel() right at this moment!&nbsp; &nbsp; value := ctx.Value("something")&nbsp; &nbsp; // Now "value" is going to be invalid.&nbsp; &nbsp; doSomething(value)}现有的上下文模型很有帮助,因为它允许工作例程仅在最安全或最方便的特定检查点检查上下文状态,而在其他情况下不必担心它。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go