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

Go语言all goroutines are asleep死锁问题排查与解决求助

解决makeThumbnails5函数的死锁问题

死锁原因

你的代码触发死锁的核心问题:

  • 未关闭输入通道:main函数中创建的ch是带缓冲通道,发送完所有文件名后未关闭。makeThumbnails5里的for f := range filenames会持续等待通道的新数据,永远无法退出这个循环,导致后续的closer goroutine根本没机会启动。
  • 多余的Wait调用:函数末尾的wg.Wait()完全冗余,且在死锁场景下根本执行不到——因为前面的循环已经阻塞了整个流程。

修复方案

  1. 在main函数中,发送完所有文件名后立即关闭通道ch,让makeThumbnails5的for range循环能正常退出。
  2. 移除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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:16:09