select有点类似逻辑判断的switch 语法,但 select 不会有输入值且只用于chan操作。select 用于从多个发送或接收chan操作中进行选择,select会阻塞直到其中有chan可以操作,

  1. package main
  2. import(
  3. "time"
  4. "fmt"
  5. )
  6. func foo(ch chan<- string){
  7. time.Sleep(time.Second)
  8. ch <-"foo"
  9. }
  10. func bar(ch chan<- string){
  11. time.Sleep(2*time.Second)
  12. ch <-"bar"
  13. }
  14. func main() {
  15. f :=make(chan string)
  16. b :=make(chan string)
  17. go foo(f)
  18. go bar(b)
  19. // 会出现阻塞
  20. select {
  21. case r :=<-f:
  22. fmt.Println(r)
  23. case r :=<-b:
  24. fmt.Println(r)
  25. }
  26. }

上面语句执行结果

  1. foo

如果有多个信道可以操作,会随机选择其中一个 case 执行,下面程序执行会随机输出

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func foo(ch chan<- string){
  7. ch <-"foo"
  8. }
  9. func bar(ch chan<- string){
  10. ch <-"bar"
  11. }
  12. func main() {
  13. f :=make(chan string)
  14. b :=make(chan string)
  15. go bar(b)
  16. go foo(f)
  17. time.Sleep(time.Second) // 为了演示随机输出 加一个延时
  18. // 会出现阻塞
  19. select {
  20. case r :=<-f:
  21. fmt.Println(r)
  22. case r :=<-b:
  23. fmt.Println(r)
  24. }
  25. }

Default

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func foo(ch chan<- string){
  6. ch <-"foo"
  7. }
  8. func bar(ch chan<- string){
  9. ch <-"bar"
  10. }
  11. func main() {
  12. f :=make(chan string)
  13. b :=make(chan string)
  14. go bar(b)
  15. go foo(f)
  16. // 1执行default 2 然后会随机打印<-f 或者<-b
  17. for {
  18. select {
  19. case r :=<-f:
  20. fmt.Println(r)
  21. return
  22. case r :=<-b:
  23. fmt.Println(r)
  24. return
  25. default:
  26. fmt.Println("default")
  27. }
  28. }
  29. }

上面会首先打印default,剩下的会随机打印f或者b的chan输出

超时控制

time.After方法,它返回一个类型为<-chan Time的单向的channel,在指定的时间发送一个当前时间给返回的channel中。

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func foo(ch chan<- string){
  7. time.Sleep(3*time.Second)
  8. ch <-"foo"
  9. }
  10. func bar(ch chan<- string){
  11. time.Sleep(2*time.Second)
  12. ch <-"bar"
  13. }
  14. func main() {
  15. f :=make(chan string)
  16. b :=make(chan string)
  17. go bar(b)
  18. go foo(f)
  19. // 会出现超时
  20. select {
  21. case r :=<-f:
  22. fmt.Println(r)
  23. case r :=<-b:
  24. fmt.Println(r)
  25. case <-time.After(time.Second):
  26. fmt.Println("time out")
  27. }
  28. }

执行结果

  1. time out

空 select

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("hello world")
  5. select {
  6. }
  7. }

空 select 语句没有 case 分支,所以便一直阻塞引起死锁。需要注意