为了账号安全,请及时绑定邮箱和手机立即绑定

所有 goroutine 都睡着了,陷入僵局

所有 goroutine 都睡着了,陷入僵局

Go
智慧大石 2023-07-10 16:30:57
似乎无法弄清楚为什么我收到错误消息:致命错误:所有 goroutine 都在睡觉 - 死锁!。我怀疑下面的块中发生了竞争条件,该条件只能在通道关闭后执行。我认为添加同步 WaitGroup 会有所帮助,但这只会给我带来这种僵局。我所看到的与我在网上看到的示例很接近,所以我不确定这里出了什么问题。func S3UploadFolder(instance *confighelper.Instance, sess *session.Session,     srcFolder string, bucketName string) (err error) {    log.Println("S3UploadFolder", srcFolder, bucketName)    wg := &sync.WaitGroup{}    // find files recursively    walker := make(fileWalk)    wg.Add(1)    go func() {        // Gather the files to upload by walking the path recursively        if err := filepath.Walk(srcFolder, walker.Walk); err != nil {            log.Fatalln("Walk failed:", err)        }        wg.Done()        close(walker)    }()    wg.Wait()    for path := range walker {    // THE GO routine above needs to have finished by the time this for loop        // ranges over the channel         fmt.Println(path) }return}type fileWalk chan stringfunc (f fileWalk) Walk(path string, info os.FileInfo, err error) error {    if err != nil {        return err    }    if !info.IsDir() {        f <- path    }    return nil}
查看完整描述

2 回答

?
牛魔王的故事

TA贡献1830条经验 获得超3个赞

该walker通道是无缓冲的。在发送方和接收方准备就绪之前,无缓冲通道上的通信不会继续进行。


死锁是这样的:主 goroutine 通过调用 wg.Done() 等待 walker goroutine 完成。walker goroutine 等待主 goroutine 在通道上接收。


通过删除与等待组相关的所有代码来修复程序。不需要等待组。在主 goroutine 中的通道范围不会完成,直到通道被 walker goroutine 关闭。在步行完成之前,walker goroutine 不会关闭通道。不需要其他协调。


您还可以通过删除 goroutine 和通道来修复代码:


err := filepath.Walk(srcFolder, func(path string, info os.FileInfo, err error) error {

    if err != nil {

        return err

    }

    if info.IsDir() {

        return nil

    }


    // Insert body of for path := range walker here ... 

    fmt.Println(path)


    return nil

})

if err != nil {

    log.Fatal(err)

}

另一种选择是创建一个容量大于将要遍历的文件数量的缓冲通道,但这需要提前知道文件数量,并且与在切片中收集文件名相比没有任何好处。


查看完整回答
反对 回复 2023-07-10
?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

如所写(和所示),在运行循环之前绝对不能调用。您可以(但不需要)在循环终止时调用。您根本不需要该变量。wg.Wait()for path := range walkerwg.Wait()wg

你的评论说:

// THE GO routine above needs to have finished by the time this for loop 
// ranges over the channel

但是循环中没有任何东西for要求函数完成,并且有一些东西(这里的总体策略)要求 goroutine不能在 send 中被阻塞,因为for只有当发送者(goroutine)时循环才会完成。关闭通道。

查看完整回答
反对 回复 2023-07-10
  • 2 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信