select语句用来处理与channel有关的I/O操作。
语法:
- 每个case都必须是一个通信;
- 所有channel表达式和被发送的表达式都会被求值;
- 任意某个通道可以运行,它就执行,其他被忽略;
- 多个case可以运行,随机选一个执行;
- 都不可以运行,有default,执行default,没有就阻塞,直到某个通信可以运行,且不会重新对表达式求值;
- 一个select最多执行一次case里的代码,需要一直检测case,外层加for循环;
- case里的break只退出当前select,和for循环无关;
示例一,执行default:
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(time.Second)
ch1 <- 1
}()
go func() {
time.Sleep(time.Second)
ch2 <- 2
}()
//time.Sleep(2*time.Second)
select {
case i := <-ch1:
fmt.Println("ch1 receive:", i)
case i := <-ch2:
fmt.Println("ch2 receive:", i)
default:
fmt.Println("no i/o operation")
}
}
结果总是打印:no i/o operation,因为当主线程走到select时,两个channel所在goroutine里的channel还没有等待写入,输出就会阻塞,执行default。
示例二,随机执行case:
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(time.Second)
ch1 <- 1
}()
go func() {
time.Sleep(time.Second)
ch2 <- 2
}()
time.Sleep(2 * time.Second)
select {
case i := <-ch1:
fmt.Println("ch1 receive:", i)
case i := <-ch2:
fmt.Println("ch2 receive:", i)
default:
fmt.Println("no i/o operation")
}
}
结果随机打印:ch1 receive: 1 或 ch2 receive: 2,因为两个channal等待写入,select里两个case都符合执行条件,随机执行。
示例三,所有表达式都会被求值:
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(time.Second)
<-ch1
}()
go func() {
time.Sleep(time.Second)
<-ch2
}()
select {
case getChannel(1, ch1) <- getValue(1):
fmt.Println("send 1 to ch1")
case getChannel(2, ch2) <- getValue(2):
fmt.Println("send 2 to ch2")
default:
fmt.Println("no i/o operation")
}
}
func getValue(i int) int {
fmt.Println("getValue:", i)
return i
}
func getChannel(i int, ch chan int) chan int {
fmt.Println("getChannel:", i)
return ch
}
结果打印如下,case所有表达式从左到右,从上到下,依次求值:
getChannel: 1
getValue: 1
getChannel: 2
getValue: 2
no i/o operation
用法:
示例一,当有goroutine运行时,用select{} 简单阻塞一下主流程:
func main() {
go func() {
for {
time.Sleep(5 * time.Second)
fmt.Println(1)
}
}()
select {}
}
示例二,实现对 channel 操作的超时设置:
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(5 * time.Second)
ch2 <- 1
}()
select {
case i:= <-ch1:
fmt.Println("ch1 receive:", i)
case <-ch2:
fmt.Println("ch1 receive timeout")
}
}
func main() {
ch := make(chan int)
select {
case i := <-ch:
fmt.Println("ch receive:", i)
case <-time.After(5 * time.Second):
fmt.Println("ch receive timeout")
}
}
示例三,检查 channel 是否已满阻塞:
func main() {
ch := make(chan int, 5)
ch <- 1
ch <- 2
ch <- 3
ch <- 4
ch <- 5
select {
case ch <- 6:
fmt.Println("send 6 to ch")
default:
fmt.Println("channel is full")
}
}
示例四,退出函数:
func main() {
stop := make(chan bool, 1)
stop <- true
select {
case i := <-stop:
if i {
fmt.Println("已退出")
return
}
default:
fmt.Println("no i/o operation")
}
fmt.Println("执行结束")
}
公众号:李田路口