为什么这个 goroutine 会泄漏?

我正在阅读“Go 中的并发”,并发现了这个 goroutine 泄漏的示例:


func main() {


    var wg sync.WaitGroup


    doWork := func(strings <-chan string) <-chan interface{} {

        completed := make(chan interface{})

        go func() {

            defer fmt.Println("doWork exited.")

            defer close(completed)

            defer wg.Done()

            fmt.Println("a")

            for s := range strings {

                fmt.Println(s)

            }

            fmt.Println("b")

        }()

        return completed

    }


    wg.Add(1)

    doWork(nil)

    fmt.Println("Waiting")

    wg.Wait()


    fmt.Println("Done.")

}

通道strings永远不会写入任何字符串,并且包含的 goroutinedoWork将在进程的生命周期内保留在内存中。


我不明白 - 为什么?


我如何理解这段代码:


原样-loop 刚刚strings被nil range跳过。当任何范围超过nil:


slice := []int{10, 20, 30, 40, 50}

slice = nil

for i := range slice {

   fmt.Println(i)

}

fmt.Println("Done")

fmt.Println("doWork exited.")将被处决


close(completed)将被处决

但我看到它是这样工作的。为什么 ?


幕布斯7119047
浏览 116回答 1
1回答

慕斯王

由于字符串为零,因此范围循环被跳过。这个假设是不正确的。在 Go 中,从nil通道读取总是会阻塞。这是在语言规范中定义的(感谢 @peterSO 挖掘出链接):从零通道接收永远阻塞。无论如何,这种行为可以很容易地用一个最小的例子来重现:func main() {     var s chan string     <- s }这个程序永远不会完成(在操场上,它会崩溃all goroutines are asleep - deadlock)。因为从 nil 通道读取(在您的示例中为strings)将永远阻塞(因为无法将任何内容写入 nil 通道),所以 goroutinedoWork将永远不会完成,因此会发生泄漏。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go