我有一个函数可以创建一个无限期地填充通道的 goroutine,例如:
func Foo() <-chan int {
ch := make(chan int)
go func() {
defer close(ch)
for {
ch <- 1
}
}()
return ch
}
假设我们有一个消费者想在一段时间后停下来:
ch:=Foo()
<-ch
<-ch
// done
现在我想清理 goroutine 资源,包括通道。我试图为此添加一个“完成”频道,但后来我遇到了僵局:
func Foo() (<-chan int, chan<- bool) {
ch := make(chan int)
done := make(chan bool)
go func() {
defer close(ch)
for {
select {
case <-done:
return
default:
ch <- 1
}
}
}()
return ch, done
}
func main() {
ch, done := Foo()
<-ch
<-ch
done <- true
// HERE
}
现在,它似乎可以工作,但这只是因为程序退出,如果我将
// HERE
替换为一些io操作(例如:http.Get("http://google.com")
),我将面临死锁(fatal error: all goroutines are asleep - deadlock!
)。
我想知道是否有另一种方法来清理由 Foo
函数创建的生成的 goroutine 和通道。
只需在启动的 goroutine 中将
default
替换为 case
:
func Foo() (<-chan int, chan<- bool) {
ch := make(chan int)
done := make(chan bool)
go func() {
defer close(ch)
for {
select {
case <-done:
return
case ch <- 1:
}
}
}()
return ch, done
}