我正在從我的驅動程式代碼中生成 5 個作業池,并從作業池回傳錯誤。在我的主程式中,我有另一個 goroutine(goroutine A,在該 goroutine 之上添加了評論)監聽錯誤。但是當從我的錯誤通道中提取資料時,我的 defer 陳述句正在執行。但我仍然可以看到來自 goroutine 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
}
}
}
我的日志是這樣的
info spawnning worker 0
2022/03/14 01:51:44 info spawnning worker 2
2022/03/14 01:51:44 info spawnning worker 1
2022/03/14 01:51:44 info done working
2022/03/14 01:51:44 info done working
2022/03/14 01:51:44 info spawnning worker 3
2022/03/14 01:51:44 info done working
2022/03/14 01:51:44 info spawnning worker 4
2022/03/14 01:51:44 info done working
2022/03/14 01:51:44 info pushing error from 0
2022/03/14 01:51:44 info done working
2022/03/14 01:51:44 error blhgsgh 0
2022/03/14 01:51:44 error got erro1r 1 error occurred:
* myError
我有點懷疑 defer 被執行了,然后我的主要 go 例程完成然后 return 被執行,但是我能做些什么來傳播我在回傳之前從 multiErrors 附加的錯誤?
如果我嘗試使用通道同步 goroutine A 和我的主要 goroutine(我稱之為 defer 的那個),它會變成阻塞。幫助
uj5u.com熱心網友回復:
我在操場上簡化了你的代碼。
您似乎假設f.Manager.Wg.Wait()回傳時所有錯誤都已處理。然而,錯誤是在一個單獨的 goroutine ( **//go routine A**) 中處理的,你不需要等待它完成——事實上,因為你不關閉f.Manager.ErrorChangoroutine 永遠不會完成。
解決這個問題的最簡單方法是在從函式回傳之前等待 goroutine 退出。下面的示例 ( playground ) 使用通道來執行此操作,但WaitGroup如果您愿意,也可以使用 a。
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 都可以比該功能更長壽(它們不會自動停止)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/443111.html
