猿问

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

似乎无法弄清楚为什么我收到错误消息:致命错误:所有 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 string


func (f fileWalk) Walk(path string, info os.FileInfo, err error) error {

    if err != nil {

        return err

    }

    if !info.IsDir() {

        f <- path

    }

    return nil

}


智慧大石
浏览 144回答 2
2回答

牛魔王的故事

该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 {&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; if info.IsDir() {&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; }&nbsp; &nbsp; // Insert body of for path := range walker here ...&nbsp;&nbsp; &nbsp; fmt.Println(path)&nbsp; &nbsp; return nil})if err != nil {&nbsp; &nbsp; log.Fatal(err)}另一种选择是创建一个容量大于将要遍历的文件数量的缓冲通道,但这需要提前知道文件数量,并且与在切片中收集文件名相比没有任何好处。

潇潇雨雨

如所写(和所示),在运行循环之前绝对不能调用。您可以(但不需要)在循环终止时调用。您根本不需要该变量。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)时循环才会完成。关闭通道。
随时随地看视频慕课网APP

相关分类

Go
我要回答