🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
select 语句 select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 select 是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。 select 随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。 语法 Go 编程语言中 select 语句的语法如下: ~~~ select { case communication clause : statement(s); case communication clause : statement(s); /* 你可以定义任意数量的 case */ default : /* 可选 */ statement(s); } ~~~ 以下描述了 select 语句的语法: ~~~ 每个case都必须是一个通信 所有channel表达式都会被求值 所有被发送的表达式都会被求值 如果任意某个通信可以进行,它就执行;其他被忽略。 如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。 否则: 如果有default子句,则执行该语句。 如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。 ~~~ 实例: ~~~ package main import "fmt" func main() { var c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: fmt.Printf("received ", i1, " from c1\n") case c2 <- i2: fmt.Printf("sent ", i2, " to c2\n") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { fmt.Printf("received ", i3, " from c3\n") } else { fmt.Printf("c3 is closed\n") } default: fmt.Printf("no communication\n") } } ~~~ 以上代码执行结果为: ~~~ no communication ~~~ Golang select的使用及典型用法 基本使用 select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。 select中的case语句必须是一个channel操作 select中的default子句总是可运行的。 如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。 如果没有可运行的case语句,且有default语句,那么就会执行default的动作。 如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行 例如: ~~~ package main import "fmt" func main() { var c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: fmt.Printf("received ", i1, " from c1\n") case c2 <- i2: fmt.Printf("sent ", i2, " to c2\n") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { fmt.Printf("received ", i3, " from c3\n") } else { fmt.Printf("c3 is closed\n") } default: fmt.Printf("no communication\n") } } //输出:no communication ~~~ 典型用法 1.超时判断 ~~~ //比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行 var resChan = make(chan int) // do request func test() { select { case data := <-resChan: doData(data) case <-time.After(time.Second * 3): fmt.Println("request time out") } } func doData(data int) { //... } ~~~ 2.退出 ~~~ //主线程(协程)中如下: var shouldQuit=make(chan struct{}) fun main(){ { //loop } //...out of the loop select { case <-c.shouldQuit: cleanUp() return default: } //... } //再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行 close(shouldQuit) ~~~ 3.判断channel是否阻塞 ~~~ //在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断 ch := make (chan int, 5) //... data:=0 select { case ch <- data: default: //做相应操作,比如丢弃data。视需求而定 } ~~~