go中的select 语句

279 阅读1分钟

前言

select是go中的一个控制结构,每个case必须是通道操作,select会随机选择一个case执行操作,可以用它执行进行阻塞操作

select使用

select语句使用如下例子

package main

import (
    "fmt"
    "time"
)

func main() {

    a := make(chan int64)

    go func() {
       fmt.Println("===================11执行开始")
       time.Sleep(3 * time.Second)
       fmt.Println("===================11执行结束")
       a <- 1
    }()

    select {
    case <-time.After(2 * time.Second):
       fmt.Println("=============超时")
    case <-a:
       fmt.Println("==========执行结束")

    }
}

以下输出结果如下

image.png 因为chan没有在2秒内执行结束,所以会执行

case <-time.After(2 * time.Second)

这个操作

default语句

select提供default语句,表示如果所有case没有执行的时候,就执行default

package main

import (
    "fmt"
    "time"
)

func main() {

    a := make(chan int64)

    go func() {
       fmt.Println("===================11执行开始")
       time.Sleep(3 * time.Second)
       fmt.Println("===================11执行结束")
       a <- 1
    }()

    select {
    case <-time.After(2 * time.Second):
       fmt.Println("=============超时")
       return
    case <-a:
       fmt.Println("==========执行结束")
       return
    default:
       fmt.Println("==============执行默认")
    }
}

执行结果如下

image.png 如果有多个select语句要执行,如果没有default语句,则默认会阻塞

package main

import (
    "fmt"
    "time"
)

func main() {

    a := make(chan int64)

    b := make(chan int64)

    go func() {
       fmt.Println("===================11执行开始")
       time.Sleep(3 * time.Second)
       fmt.Println("===================11执行结束")
       a <- 1
    }()

    go func() {
       fmt.Println("===================22执行开始")
       time.Sleep(4 * time.Second)
       fmt.Println("===================22执行结束")
       b <- 2
    }()

    for i := 0; i < 2; i++ {
       select {
       case <-b:
          fmt.Println("==========执行结束")
       case <-a:
          fmt.Println("==========执行结束")
       }
    }
}

执行结果会按照顺序打印

image.png 可以使用for循环从两个通道获取数据

package main

import (
    "fmt"
    "time"
)

func main() {

    a := make(chan int64)

    go func() {
       fmt.Println("===================11执行开始")
       time.Sleep(3 * time.Second)
       fmt.Println("===================11执行结束")
       a <- 1
    }()

    for {
       select {
       case <-a:
          fmt.Println("==========执行a结束")
       default:
          fmt.Println("=========================执行default")
       }
    }
}

如果要终止无限循环,则可以在case中加个return

case <-a:
    fmt.Println("==========执行a结束")
    return

总结

select语句可以帮助处理很多情况,比如程序超时问题等,可以更好利用它