You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Goroutine未响应ctx.Done(),如何实现多场景优雅退出?

解决Go程序正常退出时监控goroutine未打印日志的问题

这个问题的核心原因是Go程序在main函数退出时会立即终止所有未完成的后台goroutine。当你的定时器正常触发后,main函数的select分支执行完毕,紧接着就会进入退出流程,执行defer函数里的cancel()——但此时main函数马上就要结束了,Go runtime不会等待监控goroutine完成后续的打印操作,导致"Stopped monitoring"还没来得及输出,程序就终止了。

解决方案:用sync.WaitGroup等待goroutine完成

我们可以通过sync.WaitGroup来让main函数等待监控goroutine执行完所有退出逻辑后再退出,同时调整cancel()的调用时机,确保信号能被及时处理。

修改后的完整代码如下:

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "sync"
    "time"
)

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    // 确保cancel最终会被调用,避免context泄漏
    defer cancel()

    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)
    defer signal.Stop(c)

    var wg sync.WaitGroup
    wg.Add(1) // 注册一个等待任务
    go func() {
        defer wg.Done() // goroutine结束时标记任务完成
        select {
        case <-c:
            fmt.Println("Got interrupt signal")
            cancel()
        case <-ctx.Done():
        }
        fmt.Println("Stopped monitoring")
    }()

    select {
    case <-ctx.Done():
        fmt.Println("notified to quit")
    case <-time.NewTimer(time.Second * 2).C:
        fmt.Println("done something")
    }

    // 主动触发context取消,通知监控goroutine退出
    cancel()
    // 等待监控goroutine完成所有操作(包括打印日志)
    wg.Wait()

    fmt.Println("Cleaned up")
}

关键修改点说明:

  1. 添加sync.WaitGroup:通过wg.Add(1)注册等待任务,监控goroutine退出前调用wg.Done(),main函数最后用wg.Wait()阻塞,直到goroutine完成。
  2. 调整cancel()和清理逻辑的顺序:将Cleaned up的打印移到wg.Wait()之后,确保监控goroutine的日志先输出。
  3. 拆分defer逻辑:原来的单个defer函数拆分成多个,让职责更清晰,同时确保signal.Stop(c)和cancel()都能被执行。

验证输出

  • 正常退出(定时器触发):
    done something
    Stopped monitoring
    Cleaned up
    
  • Ctrl+C中断退出:
    Got interrupt signal
    Stopped monitoring
    notified to quit
    Cleaned up
    

这样两种场景下的输出都符合你的预期了。

内容的提问来源于stack exchange,提问作者Ron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 06:35:03