go - 为什么这个 goroutine 会泄漏?

标签 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 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.")
}

The strings channel will never gets any strings written onto it, and the goroutine containing doWork will remain in memory for the life time of process.

我不明白 - 为什么?

我如何理解这段代码:

  • 由于 stringsnil 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) 将被执行

但我发现它是这样工作的。为什么?

最佳答案

As strings is nil range-loop just skipped.

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

Receiving from a nil channel blocks forever.

还有a post on the Go Design Patterns blog进一步阐述了这种行为并强调了它有用的一些情况。

无论如何,这种行为可以通过一个最小的示例轻松重现( playground ):

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

这个程序永远不会完成(在 Playground 上,它会崩溃,所有 goroutine 都在 sleep - 死锁)。

因为从 nil channel 读取(在您的示例中,字符串)会阻塞(永远,因为没有任何内容可以写入 nil channel ),doWork goroutine 永远不会完成,因此会泄漏。

关于go - 为什么这个 goroutine 会泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57239639/

相关文章:

go - 循环检查并发程序中的条件

database - 防止空(或数据库中的空字符串值)

node.js - 无法解密 xor-base64 文本

Go:基本的 for 循环和 strconv

go - 无法按键获取 gorilla session 值

pointers - 如何检查嵌套指针访问/方法在运行时是否无效

go - 错误处理设计-需要根据错误类型在函数堆栈的顶部处理错误,但需要在堆栈中添加信息

string - 将 uint32 转换为字符串并添加前导 0

unit-testing - 戈朗 : how to generate a net/http timeout Error to perform unit test

go - 具有多个返回值的 Const 声明