1 回答

TA貢獻1817條經驗 獲得超6個贊
如果一個 goroutine 寫入一個無緩沖的通道并且沒有其他 goroutine 從該通道讀取 - 那么寫入將永遠阻塞。這將導致 goroutine 泄漏。這就是你正在經歷的。
如果你有一個寫入通道的“生產者”goroutine,你需要一種方法來通知它停止。關閉通道不是這里的關鍵部分 - 因為通道超出范圍時會被垃圾收集。阻塞的 goroutine(永遠不會解除阻塞)被認為是泄漏,因為它永遠不會被回收,所以你真的需要 goroutine 結束。
您可以通過多種方式表示退出意圖 - 最受歡迎的兩種方式是:
一個done頻道;或者
context.Context取消
信號:完成通道
func iterator(n int, c chan int, done <-chan struct{}) {
for i := 0; i < n; i++ {
select {
case c <- i:
case <-done:
break
}
}
close(c)
fmt.Println("iterator End")
}
閱讀器協程:
c := make(chan int)
done := make(chan struct{})
go iterator(5, c, done)
for i := range c {
if i == 2 {
break
}
fmt.Println(i)
}
close(done) // signal writer goroutine to quit
信號:context.Context
func iterator(ctx context.Context, n int, c chan int) {
defer close(c)
defer fmt.Println("iterator End")
for i := 0; i < n; i++ {
select {
case c <- i:
case <-ctx.Done():
fmt.Println("canceled. Reason:", ctx.Err())
return
}
}
}
閱讀 goroutine:
func run(ctx context.Context) {
ctx, cancel := context.WithCancel(ctx)
defer cancel() // call this regardless - avoid context leaks - but signals producer your intent to stop
c := make(chan int)
go iterator(ctx, 5, c)
for i := range c {
if i == 2 {
break
}
fmt.Println(i)
}
}
https://play.golang.org/p/4-fDyCurB7t
- 1 回答
- 0 關注
- 106 瀏覽
添加回答
舉報