Go语言all goroutines are asleep死锁问题排查与解决求助
解决makeThumbnails5函数的死锁问题
死锁原因
你的代码触发死锁的核心问题:
- 未关闭输入通道:main函数中创建的
ch是带缓冲通道,发送完所有文件名后未关闭。makeThumbnails5里的for f := range filenames会持续等待通道的新数据,永远无法退出这个循环,导致后续的closer goroutine根本没机会启动。 - 多余的Wait调用:函数末尾的
wg.Wait()完全冗余,且在死锁场景下根本执行不到——因为前面的循环已经阻塞了整个流程。
修复方案
- 在main函数中,发送完所有文件名后立即关闭通道
ch,让makeThumbnails5的for range循环能正常退出。 - 移除
makeThumbnails5末尾多余的wg.Wait()调用,避免不必要的阻塞。
修复后的代码
修正后的main函数
func main() { thumbnails := os.Args[1:] /* Get a list of all the images from the CLI */ ch := make(chan string, len(thumbnails)) for _, val := range thumbnails { ch <- val } close(ch) // 关键:发送完所有数据后关闭通道 makeThumbnails5(ch) }
修正后的makeThumbnails5函数
func makeThumbnails5(filenames <-chan string) int64 { sizes := make(chan int64) var wg sync.WaitGroup for f := range filenames { wg.Add(1) // worker goroutine go func(f string) { defer wg.Done() thumb, err := thumbnail.ImageFile(f) if err != nil { log.Println(err) return } info, _ := os.Stat(thumb) sizes <- info.Size() }(f) } // closer goroutine:等待所有worker完成后关闭sizes通道 go func() { wg.Wait() close(sizes) }() var total int64 // 遍历sizes直到通道关闭,累加所有缩略图大小 for size := range sizes { total += size } return total }
关键说明
- 使用
for range遍历通道时,只有当通道被关闭且所有元素都被接收后,循环才会退出。如果通道一直开放,遍历会持续阻塞等待新元素。 - closer goroutine的作用是确保所有worker处理完成后再关闭
sizes通道,这样主goroutine的for range sizes循环能正常结束,最终计算出总大小。
内容的提问来源于stack exchange,提问作者Harrison Cramer
相关产品推荐
相关产品推荐

