select 语义

select 从一组发送或者接受操作中选择一个操作进行处理。类似于switch,但是其中的操作全都是有关channel通信的。

select 处理的步骤如下

  • 如果有一个或多个通信操作可以处理,将随机的选择一个进行处理;除此之外如果有default,则处理default case, 没有default case select就会阻塞直到有一个通信操作可以处理。

  • 如果选择的不是default case, 执行对应的通信操作。

  • 如果选择的是一个有短变量申明或赋值的接受表达式操作,那左边的表达式会被求值, 接受到的值被赋值。

  • 被选择的case的语句被执行。

在nil channel上的通信永远不能被处理,一个只有nil channel, 且没有default case的select将永远阻塞。也就是说,select不会选择一个nil channel做处理。

检测超时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan string)
defer close(ch)

go func() {
time.Sleep(2 * time.Second)
ch <- "result"
}()

select {
case v := <-ch:
fmt.Println(v)
case <-time.After(1 * time.Second):
fmt.Println("time out")
}
}

func timeConsumeFunc(ch chan<- string) {
time.Sleep(2 * time.Second)
ch <- "result"
}

输出

1
time out

判断channel是否空, 判断channnel是否满

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import "fmt"

func main() {
var done = make(chan struct{}, 1)
done <- struct{}{}

select {
case done <- struct{}{}:
default:
fmt.Println("done chan is full")
}

var ch = make(chan struct{}, 1)
select {
case <-ch:
default:
fmt.Println("ch is empty")
}
}
1
2
done chan is full
ch is empty