package main
import (
"fmt"
)
func sender(ch chan int) {
for i := 1; i <= 10; i++ {
ch <- i
}
close(ch)
}
func receiver(ch chan int) {
for num := range ch {
fmt.Println(num)
}
}
func main() {
ch := make(chan int)
go sender(ch)
go receiver(ch)
select {}
}
通道在这个过程中的作用
- 数据传递:通道
ch
作为两个协程之间的数据桥梁,sender
协程通过 ch <- i
将数字发送到通道,receiver
协程通过 num := <-ch
从通道接收数字,实现了数据在不同协程间的传递。
- 同步:通道的发送和接收操作是阻塞的。例如,当
sender
向通道发送数据时,如果此时没有 receiver
来接收,sender
协程会阻塞,直到有 receiver
接收数据;反之,receiver
协程在尝试从通道接收数据时,如果没有数据发送进来,receiver
也会阻塞,直到有数据可用。这种阻塞机制确保了协程之间的同步。
防止协程泄露的方法
- 关闭通道:在
sender
协程完成数据发送后,使用 close(ch)
关闭通道。这不仅可以告知 receiver
协程数据发送已结束,避免 receiver
无限期阻塞,还能让 receiver
中的 for... range
循环正常退出。如果不关闭通道,receiver
协程会一直阻塞在接收操作上,导致协程泄露。
- 正确使用
select
:在 main
函数中,使用 select {}
来阻塞 main
函数的退出。因为 main
函数是程序的主协程,如果 main
函数结束,整个程序就会终止,不管其他协程是否完成。select {}
会使 main
协程永远阻塞,从而保证 sender
和 receiver
协程有足够的时间完成它们的任务。