select有点类似逻辑判断的switch 语法,但 select 不会有输入值且只用于chan操作。select 用于从多个发送或接收chan操作中进行选择,select会阻塞直到其中有chan可以操作,
package mainimport("time""fmt")func foo(ch chan<- string){time.Sleep(time.Second)ch <-"foo"}func bar(ch chan<- string){time.Sleep(2*time.Second)ch <-"bar"}func main() {f :=make(chan string)b :=make(chan string)go foo(f)go bar(b)// 会出现阻塞select {case r :=<-f:fmt.Println(r)case r :=<-b:fmt.Println(r)}}
上面语句执行结果
foo
如果有多个信道可以操作,会随机选择其中一个 case 执行,下面程序执行会随机输出
package mainimport ("fmt""time")func foo(ch chan<- string){ch <-"foo"}func bar(ch chan<- string){ch <-"bar"}func main() {f :=make(chan string)b :=make(chan string)go bar(b)go foo(f)time.Sleep(time.Second) // 为了演示随机输出 加一个延时// 会出现阻塞select {case r :=<-f:fmt.Println(r)case r :=<-b:fmt.Println(r)}}
Default
package mainimport ("fmt")func foo(ch chan<- string){ch <-"foo"}func bar(ch chan<- string){ch <-"bar"}func main() {f :=make(chan string)b :=make(chan string)go bar(b)go foo(f)// 1执行default 2 然后会随机打印<-f 或者<-bfor {select {case r :=<-f:fmt.Println(r)returncase r :=<-b:fmt.Println(r)returndefault:fmt.Println("default")}}}
上面会首先打印default,剩下的会随机打印f或者b的chan输出
超时控制
time.After方法,它返回一个类型为<-chan Time的单向的channel,在指定的时间发送一个当前时间给返回的channel中。
package mainimport ("fmt""time")func foo(ch chan<- string){time.Sleep(3*time.Second)ch <-"foo"}func bar(ch chan<- string){time.Sleep(2*time.Second)ch <-"bar"}func main() {f :=make(chan string)b :=make(chan string)go bar(b)go foo(f)// 会出现超时select {case r :=<-f:fmt.Println(r)case r :=<-b:fmt.Println(r)case <-time.After(time.Second):fmt.Println("time out")}}
执行结果
time out
空 select
package mainimport "fmt"func main() {fmt.Println("hello world")select {}}
空 select 语句没有 case 分支,所以便一直阻塞引起死锁。需要注意
