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

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

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

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贡献1829条经验 获得超7个赞

我已经在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 都可以比该函数存活(它们不会自动停止)。



查看完整回答
反对 回复 2022-11-23
  • 1 回答
  • 0 关注
  • 70 浏览
慕课专栏
更多

添加回答

举报

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