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

Go语言并发deadlock问题排查与正确实现方案咨询

Go语言并发deadlock问题排查与正确实现方案咨询

嘿,我来帮你理清楚这个死锁问题到底是怎么回事,以及该怎么解决~

首先咱们先拆解一下你代码里的死锁形成过程,这样你就能明白为什么会报错了:

  1. 你创建了一个缓冲大小为2的signal channel,然后启动了一个worker goroutine,它会一直循环从signal里接收值。
  2. 假设main里的scan函数第一次往signal发送了true,此时channel里有1个元素,worker收到这个值后,同步调用了doWork。
  3. 在doWork里,你又执行了signal <- true,这时候channel的缓冲被填满了(2个元素),然后程序进入2秒的睡眠。
  4. 等睡眠结束后,worker的循环会接着接收刚才doWork发送的第二个true,然后又一次同步调用doWork。
  5. 这时候doWork里再执行signal <- true,发现channel缓冲已经满了,这个发送操作就会阻塞——而worker现在卡在doWork的发送步骤里,根本没法回到for循环去接收channel里的值,自然也没人能取走channel里的元素来腾出空间。
  6. 同时main goroutine在无限循环调用scan,如果scan也是往signal发值的话,此时也会因为缓冲满而阻塞。到这一步,所有goroutine都卡住了,Go runtime检测到没有任何goroutine能继续推进程序,就抛出了死锁错误。

那该怎么修改才能正确实现你想要的并发逻辑呢?这里给你两个可行的方案:

方案一:用goroutine异步执行doWork,避免阻塞worker循环

把同步调用doWork改成启动新的goroutine去执行,这样worker的接收循环不会被阻塞,能一直处理channel里的信号,同时doWork的执行也不会影响channel的收发:

package main

import (
    "fmt"
    "log/slog"
    "time"
)

func main() {
    signal := make(chan bool, 2)

    go func() {
        slog.Default().Info("worker started")

        for s := range signal {
            if s {
                // 启动新goroutine执行doWork,不阻塞当前接收循环
                go doWork()
            }
        }
        slog.Default().Info("worker stopped")
    }()

    // 模拟scan的触发逻辑,比如每隔1秒发一次信号
    for {
        signal <- true
        time.Sleep(1 * time.Second)
    }
}

func doWork() {
    fmt.Println("work started")
    time.Sleep(2 * time.Second)
    fmt.Println("work finished")
    
    // 如果需要重复执行doWork,直接在这里启动新的goroutine即可
    // go doWork()
}

方案二:调整触发逻辑,不依赖原channel自循环

如果你的需求是doWork执行完成后需要再次执行,完全不用通过往signal发信号的方式触发,直接在doWork里判断条件后启动新goroutine就行,这样能彻底避免channel阻塞的问题:

func doWork() {
    fmt.Println("work started")
    time.Sleep(2 * time.Second)
    fmt.Println("work finished")

    // 这里可以根据业务逻辑判断是否需要再次执行
    needRetry := true
    if needRetry {
        go doWork()
    }
}

总结一下,你原来的问题核心在于同步调用doWork并往同一个缓冲channel里发信号,导致channel满了之后发送阻塞,进而让所有goroutine都卡停。改成异步执行的方式,就能让各个goroutine独立运行,不会互相阻塞啦。

备注:内容来源于stack exchange,提问作者Jed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 08:38:02