go——select

在go的语言规范中,select中的case的执行顺序是随机的,当有多个case都可以运行时,select会随机公平地选出一个执行,其它的便不会执行

package main

import "fmt"

func main() {
    ch := make (chan int, 1)

    ch<-1
    select {
    case <-ch:
        fmt.Println("随机一")
    case <-ch:
        fmt.Println("随机二n")
    }
}

输出内容为随机一二里面的任意一个。case后面必须是channel操作,否则报错;default子句总是可运行的,所以没有default的select才会阻塞等待事件;没有运行的case,那么将会阻塞事件发生报错(死锁)

二、select的应用场景

1.timeout超时判断

package main

import (
    "fmt"
    "time"
)

func main() {
    timeout := make (chan bool, 1)
    go func() {
        time.Sleep(1*time.Second) // 休眠1s,如果超过1s还没I操作则认为超时,通知select已经超时啦~
        timeout <- true
    }()
    ch := make (chan int)
    select {
    case <- ch:
    case <- timeout:
        fmt.Println("超时啦!")
    }
}

也可以这么写

package main

import (
    "fmt"
    "time"
)

func main() {
    timeout := make (chan bool, 1)
    go func() {
        time.Sleep(1*time.Second) // 休眠1s,如果超过1s还没I操作则认为超时,通知select已经超时啦~
        timeout <- true
    }()
    ch := make (chan int)
    select {
    case <- ch:
    case <- timeout:
        fmt.Println("超时啦!")
    }
}

2.判断channel是否阻塞(或者说channel是否已经满了)

package main

import (
    "fmt"
)

func main() {
    ch := make (chan int, 1)  // 注意这里给的容量是1
    ch <- 1
    select {
    case ch <- 2:
    default:
        fmt.Println("通道channel已经满啦,塞不下东西了!")
    }
}

3.退出机制

package main

import (
    "fmt"
    "time"
)

func main() {
    i := 0
    ch := make(chan string, 0)
    defer func() {
        close(ch)
    }()

    go func() {
        DONE: 
        for {
            time.Sleep(1*time.Second)
            fmt.Println(time.Now().Unix())
            i++

            select {
            case m := <-ch:
                println(m)
                break DONE // 跳出 select 和 for 循环
            default:
            }
        }
    }()

    time.Sleep(time.Second * 4)
    ch<-"stop"
}

三、select的实现

select-case的channel操作编译成了if-else,如:

select{
case v := <-c:
  ...foo
default:
  ...bar
}

会被编译为

if selectnbrecv(&v, c) {
   ...foo
} else {

   ..bar
}

类似地

select {
case v, ok := <-c:
   ...foo
default:
   ...bar
}

会被编译为

if c!=nil && selectnbrecv2(&v, &ok, c) {
   ...foo
} else {
   ...bar
}

。、、、、、、、、

、、、、、

三、select死锁

select不注意也会导致goruntine挂起

func main() {
    ch := make(chan string)
    select {
        case <-ch:
    }
}
package main
func main() {
    select{}
}

上面两种情况都会导致goruntine挂起,不过因为是在main函数里而且只有一个goroutine,所以会直接panic

发布了43 篇原创文章 · 获赞 37 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_28119741/article/details/103193107