select有点类似逻辑判断的switch 语法,但 select 不会有输入值且只用于chan操作。select 用于从多个发送或接收chan操作中进行选择,select会阻塞直到其中有chan可以操作,
package main
import(
"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 main
import (
"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 main
import (
"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 或者<-b
for {
select {
case r :=<-f:
fmt.Println(r)
return
case r :=<-b:
fmt.Println(r)
return
default:
fmt.Println("default")
}
}
}
上面会首先打印default,剩下的会随机打印f或者b的chan输出
超时控制
time.After方法,它返回一个类型为<-chan Time的单向的channel,在指定的时间发送一个当前时间给返回的channel中。
package main
import (
"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 main
import "fmt"
func main() {
fmt.Println("hello world")
select {
}
}
空 select 语句没有 case 分支,所以便一直阻塞引起死锁。需要注意