为什么当我超时函数时不调用延迟?

当我在函数中添加延迟时,我希望它在函数结束时始终被调用。我注意到当函数超时时它不会发生。


package main


import (

    "context"

    "fmt"

    "time"

)


func service1(ctx context.Context, r *Registry) {

    ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)

    defer func() {

        r.Unset("service 1")

    }()

    r.Set("service 1")

    go service2(ctx, r)


    select {

    case <-ctx.Done():

        cancel()

        break

    }

 }


 func service2(ctx context.Context, r *Registry) {

    defer func() {

        r.Unset("service 2")

    }()


    r.Set("service 2")


    time.Sleep(time.Millisecond * 300)

 }


         type Registry struct {

    entries map[string]bool

 }


 func (r *Registry)Set(key string) {

    r.entries[key] = true

 }


 func (r *Registry)Unset(key string)  {

    r.entries[key] = false

 }


 func (r *Registry)Print() {

    for key, val := range r.entries  {

        fmt.Printf("%s -> %v\n", key, val)

    }

 }


 func NewRegistry() *Registry {

    r := Registry{}

    r.entries = make(map[string]bool)


    return &r

 }


func main() {

    r := NewRegistry()


    ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200)


    go service1(ctx, r)

    // go service3(ctx, r)


    select {

    case <-ctx.Done():

        fmt.Printf("context err: %s\n", ctx.Err())

        cancel()

    }


    r.Print()

 }

在上面的示例中,永远不会调用 defer in service2(),这就是输出的原因:


service 1 -> false

service 2 -> true

代替


service 1 -> false

service 2 -> false

我知道超时意味着“停止执行”,但对我来说执行延迟代码是合理的。我找不到对此行为的任何解释。


问题的第二部分 - 如何修改服务或Registry抵抗这种情况?


潇潇雨雨
浏览 64回答 1
1回答

手掌心

第一部分的答案f1()假设您有一个用于defer调用的函数f2(),即defer f2()。事实上,即使发生运行时恐慌,f2当且仅当完成时才会调用。现在我们关心的是在 goroutine 中使用 defer。我们还必须记住,如果 go-routine 的父函数完成退出,它就会退出。因此,如果我们defer在一个 go-routine 函数中使用,那么如果父函数完成或退出,则 go-routine 函数必须退出。由于它退出(未完成),该defer语句将不会执行。很明显,我们绘制了您程序的状态。如你所见,在第 1 毫秒,service1()先于其他人完成。因此,service2()不执行defer语句就退出,并且“服务 2”不会设置为false. 完成后service1(),它将defer执行并将“服务 1”设置为false。在第 2 毫秒,main()完成并程序结束。所以我们看看这个程序是如何执行的。第二部分的答案我尝试过的一种可能的解决方案是增加时间service1()或减少时间service2()。
打开App,查看更多内容
随时随地看视频慕课网APP