Go语言关于 goroutines 泄漏的一个问题

发布于 2022-09-11 19:11:31 字数 1125 浏览 29 评论 0

问题描述

在阅读《go语言圣经》这本数中,对 “并发的循环” 这个章节中,使用 WaitGoup 处理 goroutines 泄漏的描述未看懂,请各位指教。

书中描述说:

如果等待操作被放在了main goroutine中,在循环之前,这样的话就永远都不会结束了

我不明白这里为什么一定要把 wg.Wait() 放到一个goroutine中去执行呢?为什么放到 main goroutine 中,就永远不会结束了?

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)

func makeThumbnails6(filenames <-chan string) int64 {
    sizes := make(chan int64)
    var wg sync.WaitGroup // number of working goroutines
    for f := range filenames {
        wg.Add(1)
        // worker
        go func(f string) {
            defer wg.Done()
            thumb, err := thumbnail.ImageFile(f)
            if err != nil {
                log.Println(err)
                return
            }
            info, _ := os.Stat(thumb) // OK to ignore error
            sizes <- info.Size()
        }(f)
    }

    // closer
    go func() { // 为什么一定要在goroutine中进行执行?
        wg.Wait()
        close(sizes)
    }()

    var total int64
    for size := range sizes {
        total += size
    }
    return total
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

野却迷人 2022-09-18 19:11:31

备忘
放在之前:
worker 中的 sizes <- info.Size() 被阻塞 ,无法走到defer wg.Done()wg.Wait() 也被阻塞,那么无法走到

for size := range sizes {  
      total += size      
}

sizes没法被读取,导致死锁

放在之后:
因为没有close(sizes)

for size := range sizes {  
      total += size      
}

一直在阻塞,导致死锁

https://stackoverflow.com/que...

爱你是孤单的心事 2022-09-18 19:11:31

放在main goroutine中会死锁,无论是在chan读取之前还是之后

本质上是因为不知道会有多少个worker goroutine..(在这个例子中就是文件的数目)


放在channel读取之前, worker的写channel会阻塞

func makeThumbnails6(filenames <-chan string) int64 {
    sizes := make(chan int64)
    var wg sync.WaitGroup // number of working goroutines
    for f := range filenames {
        wg.Add(1)
        // worker
        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
    wg.Wait()      // 阻塞在这里
    close(sizes)

    var total int64
    for size := range sizes {
        total += size
    }
    return total
}

放在读取channel之后,会一直阻塞在读取channel的地方

func makeThumbnails6(filenames <-chan string) int64 {
    sizes := make(chan int64)
    var wg sync.WaitGroup // number of working goroutines
    for f := range filenames {
        wg.Add(1)
        // worker
        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)
    }



    var total int64
    for size := range sizes {   // 阻塞在这里
        total += size
    }
    
    // closer
    wg.Wait()     
    close(sizes)
    
    return total
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文