child 中的值打印在延迟后进入常规
value printing from child go routine after defer
我正在从我的驱动程序代码中生成 5 个工作池,return从工作池中查找错误。在我的主要任务中,我有另一个 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
}
func (m *Manager) Work(ctx context.Context, fn func(string, string, string) error, workerNumber int) {
log.Infof("spawnning worker %v", workerNumber)
defer m.Wg.Done()
defer log.Info("done working")
for {
select {
case t, ok := <-m.TaskChan:
if ok {
err := fn(t.CustomerName, t.CustomerId, t.Feature)
if err != nil {
log.Infof("pushing error from %v",workerNumber)
m.ErrorChan <- err
}
} else {
return
}
case <-ctx.Done():
log.Infof("closing channel %v", ctx.Err())
return
}
}
}
我的日志是这样的
信息生成工人 0
2022/03/14 01:51:44 信息产卵工人 2
2022/03/14 01:51:44 信息产卵工人 1
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息产卵工人 3
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息产卵工人 4
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息从 0
推送错误
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 错误 blhgsgh 0
2022/03/14 01:51:44 错误发生 erro1r 1 错误:
* 我的错误
我有点怀疑 defer 被执行了,然后我的主要 go 例程完成了,然后 return 被执行了,但是我能做些什么来传播我在 return 之前从 multiErrors 附加的错误正在?
如果我尝试使用通道同步 go 例程 A 和我的主要 go 例程(我调用 defer 的那个),它变得 blocking.Help appretiated
我在 the playground 中简化了您的代码。
您似乎假设当 f.Manager.Wg.Wait()
returns 时所有错误都将得到处理。然而,错误是在一个单独的 goroutine (**//go routine A**
) 中处理的,你不会等待它完成——事实上,因为你没有关闭 f.Manager.ErrorChan
goroutine 永远不会完成。
解决此问题的最简单方法是等待 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
“紧接在周围函数 returns 之前”运行。您启动的任何 goroutine 都可以比该函数存活更久(它们不会自动停止)。
我正在从我的驱动程序代码中生成 5 个工作池,return从工作池中查找错误。在我的主要任务中,我有另一个 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
}
func (m *Manager) Work(ctx context.Context, fn func(string, string, string) error, workerNumber int) {
log.Infof("spawnning worker %v", workerNumber)
defer m.Wg.Done()
defer log.Info("done working")
for {
select {
case t, ok := <-m.TaskChan:
if ok {
err := fn(t.CustomerName, t.CustomerId, t.Feature)
if err != nil {
log.Infof("pushing error from %v",workerNumber)
m.ErrorChan <- err
}
} else {
return
}
case <-ctx.Done():
log.Infof("closing channel %v", ctx.Err())
return
}
}
}
我的日志是这样的
信息生成工人 0
2022/03/14 01:51:44 信息产卵工人 2
2022/03/14 01:51:44 信息产卵工人 1
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息产卵工人 3
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息产卵工人 4
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 信息从 0
推送错误
2022/03/14 01:51:44 信息完成工作
2022/03/14 01:51:44 错误 blhgsgh 0
2022/03/14 01:51:44 错误发生 erro1r 1 错误:
* 我的错误
我有点怀疑 defer 被执行了,然后我的主要 go 例程完成了,然后 return 被执行了,但是我能做些什么来传播我在 return 之前从 multiErrors 附加的错误正在?
如果我尝试使用通道同步 go 例程 A 和我的主要 go 例程(我调用 defer 的那个),它变得 blocking.Help appretiated
我在 the playground 中简化了您的代码。
您似乎假设当 f.Manager.Wg.Wait()
returns 时所有错误都将得到处理。然而,错误是在一个单独的 goroutine (**//go routine A**
) 中处理的,你不会等待它完成——事实上,因为你没有关闭 f.Manager.ErrorChan
goroutine 永远不会完成。
解决此问题的最简单方法是等待 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
“紧接在周围函数 returns 之前”运行。您启动的任何 goroutine 都可以比该函数存活更久(它们不会自动停止)。