登录
首页 >  Golang >  Go问答

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

来源:stackoverflow

时间:2024-03-03 22:51:25 467浏览 收藏

学习知识要善于思考,思考,再思考!今天golang学习网小编就给大家带来《所有 goroutine 都睡着了,陷入僵局》,以下内容主要包含等知识点,如果你正在学习或准备学习Golang,就都不要错过本文啦~让我们一起来看看吧,能帮助到你就更好了!

问题内容

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

解决方案


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)
}

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

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

您的评论说:

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

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

(请参阅 Cerise Limón's answer 了解为什么 goroutine 在发送中被阻塞。)

今天关于《所有 goroutine 都睡着了,陷入僵局》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于的内容请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>