select是go语言当中提供的一个选择语句。select的语法类似switch语句,也属于控制语句。
那为什么select语句我们没有放在和if、switch语句一起?
因为select是配合channel通道使用的。每个 case 必须是一个通信操作,要么是发送要么是接收。
特性总结
- select {
- case communication clause :
- statement(s);
- case communication clause :
- statement(s);
- /* 你可以定义任意数量的 case */
- default : /* 可选 */
- statement(s);
- }
示例
select只能用于channel操作,每个case都必须是一个channel。且channel是读取/写入都可以。
- func main() {
- ch1 := make(chan int)
- ch2 := make(chan string)
-
- go func() {
- ch1 <- 100
- }()
-
- go func() {
- num2 := <-ch2
- fmt.Println(num2)
- }()
-
- select {
- case num1 := <-ch1: //读取channel数据
- fmt.Println("ch1中的数据是:", num1)
- case ch2 <- "201": //channel写入数据
- fmt.Println("ch2有数据写入")
- }
- }
如果多条case语句都可以执行,则随机执行一条。
示例中,两条case语句都可以执行。多次执行可以发现,case语句是随机执行其中一条的。
- func main() {
- ch1 := make(chan int)
- ch2 := make(chan int)
-
- go func() {
- ch1 <- 100
- }()
- go func() {
- ch2 <- 200
- }()
-
- select {
- case num1 := <-ch1:
- fmt.Println("ch1中的数据是:", num1)
- case num2 := <-ch2:
- fmt.Println("ch2中的数据是:", num2)
- }
- }
如果所有case语句都被阻塞,切没有default语句和超时语句,则程序会报错死锁。
- func main() {
- ch1 := make(chan int)
- ch2 := make(chan int)
-
- select {
- case <-ch1:
- fmt.Println("ch1")
- case <-ch2:
- fmt.Println("ch2")
- }
- }
如果所有case语句都阻塞,有default语句的话,就会执行default语句。
要注意如果select语句在for循环中,default语句可能会造成CPU占用过高。
- func main() {
- ch1 := make(chan int)
- ch2 := make(chan int)
-
- select {
- case num1 := <-ch1:
- fmt.Println("ch1中的数据是:", num1)
- case num2 := <-ch2:
- fmt.Println("ch2中的数据是:", num2)
- default:
- fmt.Println("通道阻塞...default")
- }
- }
一般使用超时语句代替default语句。
- func main() {
- ch1 := make(chan int)
- ch2 := make(chan int)
-
- select {
- case num1 := <-ch1:
- fmt.Println("ch1中的数据是:", num1)
- case num2 := <-ch2:
- fmt.Println("ch2中的数据是:", num2)
- case <-time.After(3 * time.Second):
- fmt.Println("timeout...")
- }
- }