Golang select 的用法

基本使用

select 是 Go 中的一个控制结构, 类似于switch 语句, 用于处理异步 IO 操作. select 语句会监听 case语句中channel 的读写操作, 当case 中 channel 读写操作为非阻塞状态(即能读写)时, 将会触发相应的动作.

select 中的 case 语句必须是一个 channel 操作
select 中的 default 子句总是可运行的
  1. 如果有多个 case 都可以运行, select 会随机公平地选出一个执行, 其他不会执行
  2. 如果没有可运行的 case 语句, 且有 default 语句, 则会执行 default 的动作
  3. 如果没有可运行的 case 语句, 且没有 default 语句, select 将阻塞, 知道某个 case 通信可以运行

package main

import "fmt"

func main() {
   var c1, c2, c3 chan int
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}

//输出:no communication

典型用法

1. 超时判断
//比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行
var resChan = make(chan int)
// do request
func test() {
    select {
    case data := <-resChan:
        doData(data)
    case <-time.After(time.Second * 3):
        fmt.Println("request time out")
    }
}

func doData(data int) {
    //...
}
2. 退出
//主线程(协程)中如下:
var shouldQuit=make(chan struct{})
fun main(){
    {
        //loop
    }
    //...out of the loop
    select {
        case <-c.shouldQuit:
            cleanUp()
            return
        default:
        }
    //...
}

//再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
close(shouldQuit)
3. 判断 channel 是否阻塞
//在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断
ch := make (chan int, 5)
//...
data:=0
select {
case ch <- data:
default:
    //做相应操作,比如丢弃data。视需求而定
}
Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计