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

Golang代码重构后出现close of closed channel panic求助

问题根因

你的panic完全是defer的使用时机和逻辑错误导致的,核心有两点:

  1. defer触发时机错误:Go中defer语句会在当前函数退出前执行,你把defer写在GetDecisListener内部的循环里,意味着GetDecisListener刚执行完return把listener返回给上层LiveDecision的瞬间,所有注册的defer就会依次执行,直接把还没开始用的listener关掉、解注册。
  2. 重复关闭同一channel:你循环了多少次就注册了多少个defer函数,所有defer都指向同一个listener变量,第一个defer执行完close(listener)后,后续的defer再执行关闭操作就会触发close of closed channel的panic,和你报错栈的信息完全匹配。
解决方案

核心逻辑是将listener的生命周期和上层HTTP请求的生命周期对齐,不要在GetDecisListener内部做清理操作,等到请求处理完毕后再统一清理:

1. 修改GetDecisListener逻辑

移除内部的defer,新增返回值记录所有注册过的key:

//GetDecisListener return listener subscribed to channels and all registered keys
func GetDecisListener(dStructs map[string]map[string]interface{}) (chan interface{}, []string, error) {
    listener := make(chan interface{})
    keys := make([]string, 0, len(dStructs))
    for r := range dStructs {
        DecisChannels[r].Register(listener)
        keys = append(keys, r)
        fmt.Printf("Done %v\n", r)
    }
    fmt.Print("Done inside\n")
    return listener, keys, nil
}

2. 修改LiveDecision逻辑

在请求层添加defer,等整个请求处理完成后再统一执行解注册、关闭channel操作:

func LiveDecision(ctx *gin.Context) {
    ...
    listener, keys, err := GetDecisListener(dStructs)
    fmt.Print("Done outside\n")
    if err != nil {return}

    // 请求结束后统一清理listener
    defer func() {
        for _, key := range keys {
            Decision(key).Unregister(listener)
        }
        close(listener)
    }()

    ctx.Stream(func(w io.Writer) bool {
        select {
        case msg := <-listener:
            // 原有消息处理逻辑
            return true
            ...
        case <-ctx.Request.Context().Done():
            // 客户端断开连接时退出stream
            return false
        }
    })
}
调整说明
  • 清理逻辑移到LiveDecision层后,defer会在整个HTTP请求处理完毕(包括Stream流推送结束、客户端断开连接)后才触发,保证listener在使用周期内始终可用
  • 所有key仅执行一次解注册,整个listener仅关闭一次,完全避免重复关闭的panic问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 15:18:00