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 关注
- 142 浏览
添加回答
举报
