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

为何Go中用go fmt.Println(<-c)读取通道会引发死锁?

无缓冲通道引发死锁的原因分析

先看你的代码:

package main

import "fmt"

func main() {
    c := make(chan int)
    go fmt.Println(<-c)
    c <- 32
}

死锁的核心在于无缓冲通道的发送和接收必须同时配对完成,缺少任意一方都会触发阻塞。

具体执行流程如下:

  • 主goroutine创建了一个无缓冲通道c。
  • 你启动了新goroutine,但Go的goroutine调度由runtime自主决定,这个新goroutine大概率还没来得及被调度执行,也就没进入等待接收的状态。
  • 主goroutine紧接着执行c <- 32,此时没有任何goroutine在等待接收该通道的值,无缓冲通道的发送操作会直接阻塞主goroutine。
  • 主goroutine阻塞后,runtime没有机会调度那个新的goroutine执行接收操作,最终所有goroutine都卡在阻塞状态,Go runtime检测到这种情况就会抛出死锁错误。

两种可行的修复方案

  1. 改用带缓冲的通道:给通道设置至少1个缓冲容量,发送操作可以先把值存入缓冲区,不用立刻等待接收方,runtime有足够时间调度新goroutine去接收:
c := make(chan int, 1) // 带1个缓冲的通道
go fmt.Println(<-c)
c <- 32
  1. 确保接收goroutine先启动:用sync.WaitGroup同步,让主goroutine等新goroutine准备好再发送,避免调度顺序问题:
package main

import (
    "fmt"
    "sync"
)

func main() {
    c := make(chan int)
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        wg.Done() // 标记goroutine已启动
        fmt.Println(<-c)
    }()
    wg.Wait() // 等待goroutine启动完成
    c <- 32
}

内容的提问来源于stack exchange,提问作者Тимур Имашев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:52:38