Go代码死锁报错:所有goroutine休眠,求排查原因
Go代码死锁原因及修复方案
死锁根源
你的代码存在两个核心问题导致死锁:
- 无缓冲Channel的阻塞循环:goroutine执行
ch <- freq时,无缓冲Channel必须有接收方才能完成发送。但主逻辑先执行wg.Wait()等待所有goroutine结束,此时所有goroutine都卡在发送Channel的步骤(没人接收),主goroutine又卡在等待WaitGroup完成,双方互相阻塞形成死锁。 - Channel未关闭导致后续阻塞:哪怕改用带缓冲Channel,所有goroutine发送完数据后,主goroutine的
for n := range ch会一直等待新数据,因为Channel没被关闭,最终还是会触发死锁。
修复后的代码
package main import ( "fmt" "sync" ) func findMax(nums []int32) int32 { max := nums[0] for _, n := range nums { if n > max { max = n } } return max } func findFreq(nums []int32, n int32) int32 { mp := make(map[int32]int32) for _, num := range nums { mp[num]++ // 简化map计数逻辑,和原代码效果一致 } if f, ok := mp[n]; ok { return f } return -1 } func performWork(ch chan int32, nums []int32, q int32, wg *sync.WaitGroup) { defer wg.Done() seg := nums[q-1:] max := findMax(seg) freq := findFreq(seg, max) ch <- freq } func frequencyOfMaxValue(numbers []int32, q []int32) []int32 { res := []int32{} var wg sync.WaitGroup // 创建大小等于查询数量的带缓冲Channel,避免goroutine发送时阻塞 ch := make(chan int32, len(q)) for _, query := range q { wg.Add(1) go performWork(ch, numbers, query, &wg) } // 启动单独goroutine,等待所有任务完成后关闭Channel go func() { wg.Wait() close(ch) }() // 读取Channel中所有数据,Channel关闭后range会自动退出 for n := range ch { res = append(res, n) } return res } func main() { nums := []int32{5, 4, 5, 3, 2} queries := []int32{1, 2, 3, 4, 5} fmt.Println(frequencyOfMaxValue(nums, queries)) }
关键修复点
- 使用带缓冲Channel,大小与查询数量一致,保证每个goroutine都能顺利发送数据而不阻塞。
- 新增匿名goroutine,在WaitGroup完成后关闭Channel,让主goroutine的
range循环在读取完所有数据后自动终止。 - 简化了
findFreq的map计数逻辑,保持原业务逻辑不变的同时提升可读性。
内容的提问来源于stack exchange,提问作者kharlezaizen
相关产品推荐
相关产品推荐

