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

《Go程序设计语言》中goroutine与channel相关死锁问题求解

Go channel死锁触发原因解答

第243页代码去掉go关键字后的死锁触发逻辑

首先明确两个前提:

  • 代码中的worklist和unseenLinks均为无缓冲channel,发送、接收操作必须双方同时就绪才能完成,否则执行操作的goroutine会直接阻塞
  • 去掉go关键字后,原来的异步发送逻辑go func() { worklist <- foundLinks }()变成了在爬取goroutine内同步执行worklist <- foundLinks

死锁的触发流程如下:

  1. 程序启动后,初始命令行参数被送入worklist,主goroutine从worklist拿到初始链接列表,去重后往unseenLinks发送未爬取过的链接
  2. 20个爬取goroutine从unseenLinks拿到链接执行crawl操作,爬取完成后需要往worklist发送新抓到的链接列表;因为改成了同步发送,所以这个操作会直接阻塞当前爬取goroutine,直到主goroutine从worklist接收数据才能解除阻塞
  3. 当所有20个爬取goroutine都进入「等待往worklist发送数据」的阻塞状态时,就没有任何goroutine在监听、接收unseenLinks的数据了
  4. 此时主goroutine还在处理之前的链接列表,遇到下一个未爬取过的链接时,会执行unseenLinks <- link,但没有空闲的爬取goroutine接收这个发送请求,主goroutine直接阻塞在这一步
  5. 最终所有goroutine都陷入阻塞:主goroutine等unseenLinks的接收方,所有爬取goroutine等worklist的接收方,没有任何goroutine可以继续运行,死锁触发。

原来带go的写法不会触发死锁的原因是:发送worklist的操作放在了独立的临时goroutine中执行,爬取goroutine提交完发送任务就会立刻回到for range unseenLinks的监听状态,随时可以接收主goroutine发来的新链接,不会出现所有爬取goroutine都被阻塞的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 17:15:02