3 回答

TA貢獻1820條經驗 獲得超2個贊
你用錯誤組試過嗎?它內置了上下文取消功能:
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
// "golang.org/x/sync/errgroup"
wg, ctx := errgroup.WithContext(ctx)
wg.Go(func() error {
return eng.Watcher(ctx, wg)
})
wg.Go(func() error {
return eng.Suspender(ctx, wg)
})
wg.Go(func() error {
defer cancel()
<-done
return nil
})
err := wg.Wait()
if err != nil {
log.Print(err)
}
log.Print("receive shutdown")
log.Print("controller exited properly")

TA貢獻1816條經驗 獲得超6個贊
Suspenderin和 in中的代碼Watcher不會通過Done()方法調用遞減等待組計數器 - 無限執行背后的原因。
老實說,忘記這樣的小事是很正常的。這就是為什么作為 Go 中的標準一般做法,建議在一開始就使用defer和處理關鍵的事情(并且應該在 function/method 內部處理)。
更新后的實現可能看起來像
func (eng *Engine) Suspender(ctx context.Context, wg *sync.WaitGroup) error {
defer wg.Done()
// ------------------------------------
func (eng *Engine) Watcher(ctx context.Context, wg *sync.WaitGroup) error {
defer wg.Done()
contextLogger := eng.logger.WithFields(log.Fields{
另外,另一個建議是查看主例程,總是建議傳遞context by value給正在調用的任何 go-routine 或方法調用 (lambda)。這種方法使開發人員免于遇到許多不易被發現的與程序相關的錯誤。
go func(ctx context.Context) {
err := eng.Watcher(ctx, wg)
if err != nil {
cancel()
}
}(ctx)
Edit-1:(精確解)
如前所述,嘗試使用 go 例程中的值傳遞上下文。否則,兩個 go 例程都將使用單個上下文(因為您正在引用它)并且只會ctx.Done()觸發一個。通過ctx作為值傳遞,在 Go 中創建了 2 個單獨的子上下文。在使用 cancel() 關閉父級時 - 兩個子級獨立觸發ctx.Done()。

TA貢獻2019條經驗 獲得超9個贊
從表面上看,代碼看起來不錯。唯一能想到的就是它忙于“dostuff”。在調試器中逐步執行與計時相關的代碼可能會很棘手,因此請嘗試添加一些日志記錄:
case <-ticker.C:
log.Println("doing stuff")
//dostuff
log.Println("done stuff")
(我還假設您正在某處調用wg.Done()您的 go-routines,但如果它們丟失,那不會是您描述的問題的原因。)
- 3 回答
- 0 關注
- 134 瀏覽
添加回答
舉報