我有一个函数创建一个没有缓冲区的通道。该函数继续创建写入所述通道的若干其他并发匿名函数。然后该函数继续等待通道上的输入,然后返回该值。
见下面的例子
package main
import (
"time"
"fmt"
"strconv"
"math/rand"
)
func main() {
for{
text := foo()
fmt.Println(text)
time.Sleep(time.Second)
}
}
func foo() string {
ch := make(chan string)
for i := 0; i < 10; i++ {
// Create some threads
go func(i int) {
time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
ch <- strconv.Itoa(i)
}(i)
}
return <- ch
}
即使整个函数(例如foo)“死”,仍在等待通道的匿名函数会发生什么?
他们会被收集为垃圾,还是他们会永远徘徊在我的计算机内存的边缘(或者直到我杀死主线程)吃掉它,在绝望的尝试中传递他们的最后一条消息然后传递?
答案 0 :(得分:2)
你有一个goroutine泄漏。
package main
import (
"fmt"
"math/rand"
"runtime"
"strconv"
"time"
)
func main() {
for {
text := foo()
fmt.Println(text, "NumGoroutine", runtime.NumGoroutine())
time.Sleep(time.Second)
}
}
func foo() string {
ch := make(chan string)
for i := 0; i < 10; i++ {
// Create some threads
go func(i int) {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
ch <- strconv.Itoa(i)
}(i)
}
return <-ch
}
输出:
$ go run leak.go
4 NumGoroutine 10
4 NumGoroutine 20
0 NumGoroutine 28
8 NumGoroutine 37
2 NumGoroutine 46
8 NumGoroutine 55
2 NumGoroutine 64
3 NumGoroutine 73
8 NumGoroutine 82
1 NumGoroutine 91
4 NumGoroutine 100
<<--SNIP-->>
4 NumGoroutine 4006
7 NumGoroutine 4015
6 NumGoroutine 4024
9 NumGoroutine 4033
9 NumGoroutine 4042
9 NumGoroutine 4051
1 NumGoroutine 4060
0 NumGoroutine 4069
4 NumGoroutine 4078
0 NumGoroutine 4087
6 NumGoroutine 4096
^Csignal: interrupt
$
就像内存泄漏一样,goroutine泄漏也很糟糕。
有些背景,请参阅Go: proposal: runtime: garbage collect goroutines blocked forever #19702: Closed.