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

Go语言for-select-quit模式停止goroutine的执行逻辑疑问

问题解答

核心结论

你当前的代码实现中,调用close(quit)时如果FnBusy仍在执行,一定会等待该函数完全执行完成后,才会处理quit信号。

原因解释

  • Go语言的select语句仅会在当前所有待监听case都处于未触发状态时,才会阻塞等待信号。当<-ticker.C触发后,代码逻辑就进入FnBusy执行流程,此时整个goroutine正阻塞在FnBusy的time.Sleep调用上,根本没有进入下一轮循环的select监听逻辑,所以就算quit通道已经关闭,也无法被感知,必须等FnBusy执行返回,回到for循环的select语句时,才会读取到quit的关闭信号。
  • 你给出的测试输出还暴露了另一个问题:当FnBusy执行完成回到select时,quit已经关闭(可读)、ticker.C也有堆积的tick事件(可读),Go的select在多个case同时就绪时会伪随机选择一个执行,所以才会出现连续三次触发FnBusy之后才命中quit退出的情况,整个测试跑了3分钟才结束。

优化方案

如果希望关闭quit时可以中断正在执行的FnBusy,可以通过上下文实现,修改后的示例代码如下:

func FnBusy(ctx context.Context) {
    log.Println("Entering FnBusy")
    select {
    case <-ctx.Done():
        log.Println("FnBusy interrupted")
        return
    case <-time.After(1 * time.Minute):
        log.Println("Exiting FnBusy")
    }
}

func TestGoRoutineStop(t *testing.T) {
    quit := make(chan interface{})
    ctx, cancel := context.WithCancel(context.Background())
    wg := sync.WaitGroup{}
    ticker := time.NewTicker(10 * time.Millisecond)
    defer ticker.Stop()
    defer cancel()
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            select {
            case <-quit:
                log.Println("Quit Called")
                cancel()
                return
            case <-ticker.C:
                FnBusy(ctx)
            }
        }
    }()

    time.Sleep(150 * time.Millisecond)
    close(quit)
    wg.Wait()
}

如果希望优先处理quit信号、避免quit就绪后还继续执行FnBusy,可以提前做非阻塞的quit检查:

go func() {
    defer wg.Done()
    for {
        // 优先检查quit信号
        select {
        case <-quit:
            log.Println("Quit Called")
            return
        default:
        }
        select {
        case <-quit:
            log.Println("Quit Called")
            return
        case <-ticker.C:
            FnBusy()
        }
    }
}()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 05:57:02