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 关注
- 104 浏览
添加回答
举报