我正在阅读“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
将永远不会完成,因此会发生泄漏。
- 1 回答
- 0 关注
- 110 浏览
添加回答
举报
0/150
提交
取消