select详解

只争朝夕々 · · 168 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

语法具体定义参考官方定义

https://golang.org/ref/spec#Select_statements

select语句执行分以下一个步骤执行

  • 所有channel表达式都会被求值、所有被发送的表达式都会被求值。求值顺序:自上而下、从左到右。
  • 如果有一个或多个通信操作可以完成,则Go运行时系统会伪随机的选择一个执行。否则,如果有default分支,则执行default分支语句,如果连default都没有,则select语句会一直阻塞,直到至少有一个通信操作可以进行。

案例分析

所有channel表达式都会被求值、所有被发送的表达式都会被求值。求值顺序:自上而下、从左到右

func main() {
    var ch1 chan int
    var ch2 chan int
    var chs = []chan int{ch1, ch2}
    var numbers = []int{1, 2, 3, 4, 5}

    getNumber := func(i int) int {
        fmt.Printf("numbers[%d]\n", i)
        return numbers[i]
    }

    getChan := func(i int) chan int {
        fmt.Printf("chs[%d]\n", i)
        return chs[i]
    }

    select {
    case getChan(0) <- getNumber(2):
        fmt.Println("1th case is selected.")
    case getChan(1) <- getNumber(3):
        fmt.Println("2th case is selected.")
    default:
        fmt.Println("default case")
    }
}

输出:

chs[0]
numbers[2]
chs[1]
numbers[3]
default case

Process finished with exit code 0

如果有一个或多个通信操作可以完成,则Go运行时系统会伪随机的选择一个执行。否则,如果有default分支,则执行default分支语句,如果连default都没有,则select语句会一直阻塞,直到至少有一个通信操作可以进行

  • 所有case语句都被阻塞时,如果有default语句,执行default语句
func main() {
    start := time.Now()
    ch1 := make(chan int)
    ch2 := make(chan int)

        go func() {
        time.Sleep(2 * time.Second)
        ch1 <- 3
    }()

    go func() {
        time.Sleep(3 * time.Second)
        ch2 <- 5
    }()

    fmt.Println("blocking on read...")

    select {
    case <-ch1:
        fmt.Printf("ch1 case...")
    case <-ch2:
        fmt.Printf("ch2 case...")
    default:
        fmt.Printf("default case...")
    }
}

输出:

blocking on read...
default case...
Process finished with exit code 0
  • 所有case语句都被阻塞时,当没有default语句时,select阻塞等待
func main() {
    start := time.Now()
        ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        time.Sleep(2 * time.Second)
        ch1 <- 3
    }()

    go func() {
        time.Sleep(3 * time.Second)
        ch2 <- 5
    }()

    fmt.Println("blocking on read...")

    select {
    case <-ch1:
        fmt.Printf("ch1 case...")
    case <-ch2:
        fmt.Printf("ch2 case...")
    }
}

输出:

blocking on read...
ch1 case...
Process finished with exit code 0
  • 当多个case语句都可以被执行时,伪随机的选择一个执行
func main() {
    start := time.Now()
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- 3
    }()

    go func() {
        time.Sleep(1 * time.Second)
        ch2 <- 5
    }()

    fmt.Println("blocking on read...")

    select {
    case <-ch1:
        fmt.Printf("ch1 case...")
    case <-ch2:
        fmt.Printf("ch2 case...")
    }
}

输出:

blocking on read...
ch1 case...
Process finished with exit code 0
blocking on read...
ch2 case...
Process finished with exit code 0

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:只争朝夕々

查看原文:select详解

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

168 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传