为了账号安全,请及时绑定邮箱和手机立即绑定

为什么这个 goroutine 会泄漏?

为什么这个 goroutine 会泄漏?

Go
幕布斯7119047 2023-07-10 10:50:28
我正在阅读“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 = nilfor i := range slice {   fmt.Println(i)}fmt.Println("Done")fmt.Println("doWork exited.")将被处决close(completed)将被处决但我看到它是这样工作的。为什么 ?
查看完整描述

1 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

由于字符串为零,因此范围循环被跳过。

这个假设是不正确的。在 Go 中,从nil通道读取总是会阻塞。这是在语言规范中定义的(感谢 @peterSO 挖掘出链接):

从零通道接收永远阻塞。

无论如何,这种行为可以很容易地用一个最小的例子来重现:

func main() { 
   var s chan string
    <- s
}

这个程序永远不会完成(在操场上,它会崩溃all goroutines are asleep - deadlock)。

因为从 nil 通道读取(在您的示例中为strings)将永远阻塞(因为无法将任何内容写入 nil 通道),所以 goroutinedoWork将永远不会完成,因此会发生泄漏。


查看完整回答
反对 回复 2023-07-10
  • 1 回答
  • 0 关注
  • 110 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信