首页 > 编程笔记 > Go语言笔记 阅读:3

Go语言select语句的用法(非常详细)

在 Go 语句中,通道存储数据达到上限的时候,再往通道中写入数据就会提示异常,通道没有存储数据的时候,从通道中读取数据也会提示异常。

在程序运行过程中,我们无法准确预估通道是否有数据或者数据存储是否已达上限,为了解决程序执行异常的问题,可以使用关键字 select 实现。

select 是 Go 语言的一个控制结构语句,语法结构与 switch 语句相似,但仅适用于通道,它可以与 case 和 default 搭配使用,每个 case 必须是一个通信操作,操作方式是执行数据写入或数据读取,也就是说,select 不仅能处理通道阻塞的异常,还能同时处理多个通道变量。

select 语法如下:
select {
   case ch:
      do something;
   case ch:
      do something;
   /* 定义任意数量的case */
   default : /* 可选 */
      do something;
}
语法说明如下:
根据 select 的语法格式,我们使用多通道的方式实现数据的存储和读写,示例如下:
package main

import (
   "fmt"
   "time"
)

func sent_data(ch, ch1 chan int) {
   for i := 0; i < 5; i++ {
        select {
        case ch <- i:
             fmt.Printf("ch写入数据:%v\n", i)
        case ch1 <- i:
             fmt.Printf("ch1写入数据:%v\n", i)
        }
   }
}

func get_data(ch, ch1 chan int) {
   for i := 0; i < 5; i++ {
        select {
        case i := <-ch:
             fmt.Printf("ch接收数据:%v\n", i)
        case i := <-ch1:
             fmt.Printf("ch1接收数据:%v\n", i)
        }
   }
}

func main() {
   // 创建通道
   ch := make(chan int)
   ch1 := make(chan int)
   go sent_data(ch, ch1)
   go get_data(ch, ch1)
   time.Sleep(5 * time.Second)
}
运行上述代码,运行结果为:

ch1写入数据:0
ch1接收数据:0
ch接收数据:1
ch写入数据:1
ch1写入数据:2
ch1接收数据:2
ch接收数据:3
ch写入数据:3
ch写入数据:4
ch接收数据:4

上述示例定义了函数 sent_data() 和 get_data(),主函数 main() 分别对函数执行并发操作,说明如下:

1) 函数 sent_data() 设有两个参数,分别为 ch 和 ch1,代表两个不同的通道变量,函数执行 5 次循环,每次循环使用 select 和 case 分别对通道变量 ch 或 ch1 执行数据写入操作。

2) 函数 get_data() 的定义过程与 sent_data() 相似,它对通道变量 ch 或 ch1 执行数据读取操作。

3) 主函数 main() 创建通道变量 ch 和 ch1,使用关键字 go 分别对函数 sent_data() 和 get_data() 执行并发操作,最后设置等待延时 5 秒,主要等待并发程序执行完成。

4) 通道变量 ch 和 ch1 设为无缓冲通道,通道数据写入和读取必须同步,否则造成阻塞。函数 sent_data() 和 get_data() 的 select…case 语句没有设置 default 语句,因为通道变量 ch 和 ch1 分别由不同函数操作,必然存在阻塞情况,如果设置 default 语句,程序会因为通道阻塞而无法实现数据的写入和读取。

综上所述,使用 select…case…default 语句可以防止通道阻塞而提示程序异常,同时还能处理多个通道。如果没有设置 default 语句,当通道遇到阻塞的时候,select 也会处于阻塞,这样很容易造成程序无止境地等待,因此在使用 select 语句的时候需考虑这种极端情况。

相关文章