为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
潇潇雨雨 2023-05-08 14:36:25
当我在函数中添加延迟时,我希望它在函数结束时始终被调用。我注意到当函数超时时它不会发生。package mainimport (    "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 -> falseservice 2 -> true代替service 1 -> falseservice 2 -> false我知道超时意味着“停止执行”,但对我来说执行延迟代码是合理的。我找不到对此行为的任何解释。问题的第二部分 - 如何修改服务或Registry抵抗这种情况?
查看完整描述

1 回答

?
手掌心

TA贡献1942条经验 获得超3个赞

第一部分的答案

f1()假设您有一个用于defer调用的函数f2(),即defer f2()。事实上,即使发生运行时恐慌,f2当且仅当完成时才会调用。

现在我们关心的是在 goroutine 中使用 defer。我们还必须记住,如果 go-routine 的父函数完成退出,它就会退出。

因此,如果我们defer在一个 go-routine 函数中使用,那么如果父函数完成或退出,则 go-routine 函数必须退出。由于它退出(未完成),该defer语句将不会执行。很明显,我们绘制了您程序的状态。

//img3.sycdn.imooc.com/6458987e0001a2be06520361.jpg

如你所见,

  • 在第 1 毫秒,service1()先于其他人完成。因此,service2()不执行defer语句就退出,并且“服务 2”不会设置为false. 完成后service1(),它将defer执行并将“服务 1”设置为false

  • 在第 2 毫秒,main()完成并程序结束。

所以我们看看这个程序是如何执行的。

第二部分的答案

我尝试过的一种可能的解决方案是增加时间service1()或减少时间service2()


查看完整回答
反对 回复 2023-05-08
  • 1 回答
  • 0 关注
  • 60 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信