为什么这个goroutine会泄露?

为什么这个goroutine会泄露?,go,Go,我正在阅读《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 exit

我正在阅读《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.")
}
fmt.PrintlndoWork已退出。将被执行

已完成的关闭将被执行 但我看到它是这样工作的。为什么?

因为字符串是零范围的,所以刚才跳过了循环


这种假设是不正确的。在Go中,从零通道读取的数据将始终被阻塞。这在感谢@peterSO挖掘链接中定义:

从零通道接收将永远阻塞

还有一个例子进一步阐述了这种行为,并强调了它在某些情况下是有用的

无论如何,只要举一个简单的例子,就可以很容易地再现这种行为:

这个程序永远不会在操场上完成,它会崩溃,所有的goroutines都处于休眠状态-死锁

在本例中,由于从nil通道读取,字符串将永远阻塞,因为无法将任何内容写入nil通道,因此doWork goroutine将永远不会完成,因此会泄漏

因为字符串是零范围的,所以刚才跳过了循环


这种假设是不正确的。在Go中,从零通道读取的数据将始终被阻塞。这在感谢@peterSO挖掘链接中定义:

从零通道接收将永远阻塞

还有一个例子进一步阐述了这种行为,并强调了它在某些情况下是有用的

无论如何,只要举一个简单的例子,就可以很容易地再现这种行为:

这个程序永远不会在操场上完成,它会崩溃,所有的goroutines都处于休眠状态-死锁


在本例中,由于从nil通道读取,字符串将永远阻塞,因为无法将任何内容写入nil通道,所以doWork goroutine将永远不会完成,因此会泄漏。

从nil通道永久阻塞接收。range语句不会被跳过,它不会终止,因为通道从未关闭。永远从零通道块接收。range语句不会被跳过,它不会终止,因为通道从未关闭。在Go中,从零通道读取的数据将始终被阻塞。我还没有找到任何关于这种行为的官方文件从一个零信道块接收信号@peterSO感谢您提供规范的链接!我已经相应地更新了答案。在围棋中,从零频道读取总是会被阻塞。我还没有找到任何关于这种行为的官方文件从一个零信道块接收信号@peterSO感谢您提供规范的链接!我已经相应地更新了答案。
slice := []int{10, 20, 30, 40, 50}
slice = nil
for i := range slice {
   fmt.Println(i)
}
fmt.Println("Done")
func main() {
    var s chan string
    <- s
}