第一种方法,关闭channel。就是借助 channel 的 close 机制来完成对 goroutine 的精确控制。
func main() {
ch := make(chan string, 6)
go func() {
for {
v, ok := <-ch
if !ok {
fmt.Println("结束")
return
}
fmt.Println(v)
}
}()
ch <- "煎鱼还没进锅里..."
ch <- "煎鱼进脑子里了!"
close(ch)
time.Sleep(time.Second)
}
第二种方法,定期轮询 channel。是更为精细的方法,其结合了第一种方法和类似信号量的处理方式。
func main() {
ch := make(chan string, 6)
done := make(chan struct{})
go func() {
for {
select {
case ch <- "脑子进煎鱼了":
case <-done:
close(ch)
return
}
time.Sleep(100 * time.Millisecond)
}
}()
go func() {
time.Sleep(3 * time.Second)
done <- struct{}{}
}()
for i := range ch {
fmt.Println("接收到的值: ", i)
}
fmt.Println("结束")
}
第三种方法,可以借助 Go 语言的上下文(context)来做 goroutine 的控制和关闭。
func main() {
ch := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
ch <- struct{}{}
return
default:
fmt.Println("煎鱼还没到锅里...")
}
time.Sleep(500 * time.Millisecond)
}
}(ctx)
go func() {
time.Sleep(3 * time.Second)
cancel()
}()
<-ch
fmt.Println("结束")
}