3 回答

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超3個(gè)贊
你用錯(cuò)誤組試過(guò)嗎?它內(nèi)置了上下文取消功能:
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貢獻(xiàn)1816條經(jīng)驗(yàn) 獲得超6個(gè)贊
Suspenderin和 in中的代碼Watcher不會(huì)通過(guò)Done()方法調(diào)用遞減等待組計(jì)數(shù)器 - 無(wú)限執(zhí)行背后的原因。
老實(shí)說(shuō),忘記這樣的小事是很正常的。這就是為什么作為 Go 中的標(biāo)準(zhǔn)一般做法,建議在一開始就使用defer和處理關(guān)鍵的事情(并且應(yīng)該在 function/method 內(nèi)部處理)。
更新后的實(shí)現(xiàn)可能看起來(lái)像
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{
另外,另一個(gè)建議是查看主例程,總是建議傳遞context by value給正在調(diào)用的任何 go-routine 或方法調(diào)用 (lambda)。這種方法使開發(fā)人員免于遇到許多不易被發(fā)現(xiàn)的與程序相關(guān)的錯(cuò)誤。
go func(ctx context.Context) {
err := eng.Watcher(ctx, wg)
if err != nil {
cancel()
}
}(ctx)
Edit-1:(精確解)
如前所述,嘗試使用 go 例程中的值傳遞上下文。否則,兩個(gè) go 例程都將使用單個(gè)上下文(因?yàn)槟谝盟┎⑶抑粫?huì)ctx.Done()觸發(fā)一個(gè)。通過(guò)ctx作為值傳遞,在 Go 中創(chuàng)建了 2 個(gè)單獨(dú)的子上下文。在使用 cancel() 關(guān)閉父級(jí)時(shí) - 兩個(gè)子級(jí)獨(dú)立觸發(fā)ctx.Done()。

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