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

孩子的价值打印在延迟后成为常规

孩子的价值打印在延迟后成为常规

Go
梦里花落0921 2022-11-23 13:56:22

我正在从我的驱动程序代码中生成 5 个工作池,并从工作池返回错误。在我的主要任务中,我有另一个 go routine(go routine A ,在那个 go routine 之上添加了注释)监听错误。但是当从我的错误通道中选取数据时,我的 defer 语句正在执行。但我仍然可以看到来自 go routine A 的日志。


func ....{

var requests []Req

        err := json.Unmarshal(Data, &requests)

        if err != nil {

            log.WithError(err).Errorf("Invalid data passed for flag type %v", proto.CreateFlagReq_SET_OF.String())

            return err

        }

        f.Manager.TaskChan = make(chan Req, 100)

        f.Manager.ErrorChan = make(chan error, 100)


        for i := 0; i < f.Manager.WorkerCount; i++ {

            f.Manager.Wg.Add(1)

           //AddToSetOfcustomers just validates before addigg to redis

            go f.Manager.Work(ctx, f.redisPool.AddToSetOfcustomers, i)

        }


        for _, request := range requests {

            f.Manager.TaskChan <- request

        }

        close(f.Manager.TaskChan)


        var errors error

        **//go routine A**

        go func() {

            for {

                select {

                case err ,ok:= <- f.Manager.ErrorChan:

                    if ok{

                        errors = multierror.Append(errors, err)

                        log.Errorf("got erro1r %v",errors)

                    }else{

                        log.Info("returning")

                        return

                    }


                }

            }

        }()

        f.Manager.Wg.Wait()


        defer log.Errorf("blhgsgh   %v %v",len(f.Manager.ErrorChan),errors)

        return errors

}


我有点怀疑 defer 被执行了,然后我的主要 go 例程完成了,然后 return 被执行了,但是我能做些什么来传播我在返回之前从 multiErrors 附加的错误?


如果我尝试使用通道同步 go routine A 和我的主要 go routine(我称之为 defer 的那个),它会变成阻塞。Help appretiated


查看完整描述

1 回答

?
千巷猫影

TA贡献1514条经验 获得超1个赞

我已经在playground中简化了您的代码。

您似乎假设f.Manager.Wg.Wait()返回时所有错误都已处理。然而,错误正在一个单独的 goroutine ( **//go routine A**) 中处理,您不会等待它完成——事实上,因为您不关闭f.Manager.ErrorChangoroutine 永远不会完成。

解决这个问题的最简单方法是等待 goroutine 退出,然后再从函数返回。下面的示例 ( playground ) 使用一个通道来执行此操作,但WaitGroup如果您愿意,也可以使用一个。

var errors []error

errDone := make(chan struct{})

go func() {

    for {

        select {

        case err, ok := <-errorChan:

            if ok {

                errors = append(errors, err)

                log.Printf("got error %v", errors)

            } else {

                log.Printf("returning")

                close(errDone)

                return

            }

        }

    }

}()

wg.Wait()


// Everything sending to errorChan is now done so we can safely close the channel

close(errorChan)

<-errDone // Wait for error handling goroutine to complete

请注意,defer“在周围函数返回之前立即运行”。您启动的任何 goroutine 都可以比该函数存活(它们不会自动停止)。



查看完整回答
反对 回复 5天前

添加回答

举报

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