Go语言select语句用法示例

发布时间:2022-8-04 09:33

多个通道 Channel 中信息的发送和接受处理的专用的语句—select 语句。select 语句会阻塞,直到其中的一个发送/接收操作准备好。select 语句和 switch 语句有点相似,但 select 语句在被执行时会选择执行其中的一个分支,且选择分支的方法完全是不相同的。

ch1 = make(chan string)
ch2 = make(chan string)
ch1 <- "server1"
ch2 <- "server1"
select {
case i := <- ch1:
  fmt.Printf("从ch1读取了数据%d", i)
case j := <- ch2:
  fmt.Printf("从ch2读取了数据%d", i)
default:
  fmt.Printf("no action...", i)
}

以上代码中,每个 case 后都只针对某个通道的接收语句,这个和 switch 不同,也没有 break。switch 语句右边是一个switch 表达式,但 select 右边是接大括号。

开始执行 select 语句时,所有跟在 case 关键字右边的表达式都会被求值,求值的顺序是自上而下,从左到右的。

使用场景

实现收发功能

select 是控制 channel 必不可少的部分,channel 的主要功能就是收发信息,基于此可以设计一个生产者消费者功能。生产者发送消息,消费者接受消息

func main(){
// 生产数据,将数据写入 channel 
  n1 := make(chan int)
go func() {
i := 0
for {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
n1 <- i
i++
}
}()
n2 := make(chan int)
go func() {
i := 0
for {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
n2 <- i
i++
}
}()
// 从 channel 中读取到数据就输出
for {
select {
case n := <-n1:
fmt.Printf("从ch1读取了数据%d", n)
case n := <-n2:
fmt.Printf("从ch1读取了数据%d", n)
}
}
}

注意事项

select 只能用于 chan 的 IO 操作select 的 case 都是并行的,case 读取到数据就执行,但是如果没有读取到且未设置 default 将导致阻塞尽量设置 default 避免没有 IO 操作发生时,select 语句一直阻塞,直到某个 case 分支命中如果是空的 select 有可能会引起死锁,所以在 select 执行过程中,必须命中某一 case 分支

select {}

防止阻塞还有一个方法:设置超时

Go语言入门之函数的定义与使用 生活杂谈

Go语言入门之函数的定义与使用

函数是一段代码的片段,包含连续的执行语句,它可以将零个或多个输入参数映射到零个或多个参数输出。函数像一个黑盒,对它的使用者隐藏实现细节。还可以在代码中通过函数调用来执行它们。 学到现在,我们使用...
利用Go语言快速实现一个极简任务调度系统 网站建设

利用Go语言快速实现一个极简任务调度系统

任务调度(Task Scheduling)是很多软件系统中的重要组成部分,字面上的意思是按照一定要求分配运行一些通常时间较长的脚本或程序。在爬虫管理平台 Crawlab 中,任务调度是其中的核心模块,...
go mock server的简易实现示例 生活杂谈

go mock server的简易实现示例

学习golang也一段时间了,看了一些书,上周又看了一本入门级的《Go语言趣学指南》,是时候检验成果了。 目的:通过读取本地mock数据,发起http请求,返回给前端,实现mock功能。 代码...
go语言中实现协程功能的两种方式及示例代码 生活杂谈

go语言中实现协程功能的两种方式及示例代码

协程本质上是一种用户态线程,不需要操作系统来进行抢占式调度,并且在真正的实现中寄存于线程中,因此系统开销极小,可以有效的提高线程任务的并发性,而避免多线程的缺点。 协程的优点:使用协程的优点是编...