Go select 详解

  • 每个 case 都必须是一个通信(IO 操作)
  • 所有 channel 表达式都会被求值(所有被发送的表达式都会被求值)
  • 如果任意某个通信可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行
    【示例一 实际测试不是随机的 因为不带缓冲区的channel是阻塞的】
  • 如果有 default 子句,则执行该语句。
  • 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。

示例一

【示例一 实际测试不是随机的?因为不带缓冲区的channel是阻塞的】

package main
import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    ch3 := make(chan int)
    quit := make(chan bool)
    //新开一个协程
    go func() {
        for {
            time.Sleep(1 * time.Second)
            select {
            case num := <-ch1:
                fmt.Println("num1 = ", num)
            case num := <-ch2:
                fmt.Println("num2 = ", num)
            case num := <-ch3:
                fmt.Println("num3 = ", num)
            case <-time.After(3 * time.Second):
                fmt.Println("超时")
                quit <- true
            }
        }
    }() //别忘了()
    for i := 0; i < 6; i++ {
        ch1 <- i
        ch3 <- i
        ch2 <- i
        //time.Sleep(time.Second)
    }
    <-quit
    fmt.Println("程序结束")
}
    
  • 执行顺序【随机】
    select 不会按照任何规则或者优先级选择到达的channel。go标准库在每次访问的时候,都会将他们顺序打乱,也就是说不能保证任何顺序
    https://segmentfault.com/a/1190000022520711
package main
func main() {
    a := make(chan bool, 100)
    b := make(chan bool, 100)
    c := make(chan bool, 100)
    for i := 0; i < 10; i++ {
        a <- true
        b <- true
        c <- true
    }
    for i := 0; i < 10; i++ {
        select {
        case <-a:
            print("< a")
        case <-b:
            print("< b")
        case <-c:
            print("< c")
        default:
            print("< default")
        }
    }
}
//程序的输出 < b< a< a< b< c< c< c< a< b< b

由于go 不会删除重复的channel,所以可以使用多次添加case来影响结果

func main() {
   a := make(chan bool, 100)
   b := make(chan bool, 100)
   c := make(chan bool, 100)
   for i := 0; i < 10; i++ {
      a <- true
      b <- true
      c <- true
   }
   for i := 0; i < 10; i++ {
      select {
      case <-a:
         print("< a")
      case <-a:
         print("< a")
      case <-a:
         print("< a")
      case <-a:
         print("< a")
      case <-a:
         print("< a")
      case <-a:
         print("< a")
      case <-a:
         print("< a")
      case <-b:
         print("< b")
      case <-c:
         print("< c")
      default:
         print("< default")
      }
   }
}
输出的结果:
< c< a< b< a< b< a< a< c< a< a

你可能感兴趣的:(Go select 详解)