select 语句是 将各种channel 绑定在一起的粘合剂; 连接各种组件在一起;
select 语句可以帮助安全地将channel 与诸如取消,超时,等待和默认值之类 的概念结合在一起。
与 switch 块不同, select 块中的case 语句没有按顺序测试,如果没有满足任何条件,执行也不会失败。
如果所有channel 都没有准备好,则阻塞状态直到 。当一个channel准备好了,这个操作就会继续,它相应的语句就会执行。
func main() {
start := time.Now()
c := make(chan interface{})
go func() {
time.Sleep(5*time.Second)
close(c)
}()
fmt.Println("Blocking on read ...")
select {
case <-c :
fmt.Printf("Unblocked %v later.\n", time.Since(start))
}
}
//Blocking on read ...
//Unblocked 5.00277253s later.
关于 select 一些问题?
当多个channel 有数据可供下游读取的时候会发生什么?
如没有 任何可用的channel 怎么办?
如果, 我们想做一些事情,但是没有可用的 channels 怎么办?
如果channel 同时可用会怎么样? 实验如下:
func main(){
c1 := make(chan interface{}); close(c1)
c2 := make(chan interface{}); close(c2)
var c1Count, c2Count int
for i := 1000; i>=0; i-- {
select {
case <- c1:
c1Count++
case <- c2:
c2Count++
}
}
fmt.Printf("c1Count: %d\nc2Count: %d\n", c1Count, c2Count)
}
//c1Count: 514
//c2Count: 487
第二个问题: 如果没有任何channel 可用,会发生什么?
第二个问题: 如果没有任何channel 可用,会发生什么?
如果没有可用的,但是你不希望 永远阻塞; 可能需要超时机制。
*/
func main(){
var c <-chan int
select {
case <-c :
case <-time.After(1 * time.Second): //注释掉 就会 deadlock ,; 该channel 返回执行后的时间;
fmt.Println("Time out.")
}
}
c<- 永远不会被 解锁(unblock), 因为我们是从 nil channel 读取的,(从nil channel 读取会阻塞)
第三个问题: 当没有可用channel 时, 我们需要做些什么?
第三个问题: 当没有可用channel 时, 我们需要做些什么?
当 select 语句中的所有channel都被阻塞时候, "select" 语句也允许你调用默认语句。
*/
func main(){
start := time.Now()
var c1, c2 <- chan int
select {
case <-c1:
case <-c2:
default:
fmt.Printf("In default after %v\n\n", time.Since(start))
}
}
//In default after 4.612µs
//In default after 2.772µs
通常 ;会看到: default 和 for-select 循环一起使用,这允许goroutine在等待另一个goroutine上报结果的同时,可以继续执行自己的操作。
func main() {
done := make(chan interface{})
go func() {
time.Sleep(5 * time.Second)
close(done)
}()
workCounter := 0
loop:
for {
select {
case <-done:
break loop
default:
}
//模拟工作行为
workCounter++
time.Sleep(1 * time.Second)
}
fmt.Printf("在收到停止信号停止以前,进行了%v 次 任务\n", workCounter)
}
//在收到停止信号停止以前,进行了5 次 任务
没有case 的select 将永远阻塞。
select{}