
上下文取消后,
在 go 语言中,使用 context.context 包可以实现协程间通信和取消。当 context 被取消后,
这是因为
导致该问题的一个示例
以下代码演示了该问题:
package main
import (
"context"
"fmt"
)
func gen(ctx context.context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.done():
fmt.println("done")
default:
n += 1
ch <- n
}
}
}()
return ch
}
func main() {
ctx, cancel := context.withcancel(context.background())
for n := range gen(ctx) {
fmt.println(n)
if n == 5 {
break
}
}
defer cancel()
}在这种情况下,for循环将在读取到第六个元素之前一直运行。这意味着,当cancel()被调用时,第六个元素已经准备好了。因此,
解决方法
可以通过关闭通道来解决此问题。当上下文被取消时,关闭通道将导致
以下代码显示了改进后的示例:
package main
import (
"context"
"fmt"
)
func gen(ctx context.Context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.Done():
fmt.Println("done")
close(ch) // 关闭通道,range结束
return
default:
n += 1
ch <- n
}
}
}()
return ch
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
cancel()
// break不能break,否则没有从ch中读取,就会一直阻塞在ch<-n
}
}
}这样,无论第六个元素是否已经准备好,










