go语言之并发Select深度理解

select的使用方法很像switch语句,但是select没有输入值,只用于信道操作。

select用于多个信道的发送或者接收信道的操作中进行选择。

语句会阻塞直到其中有信道可以操作,若有多个信道可以操作,会随机选择其中一个case执行。

func service1(ch chan string) {
   time.Sleep(2 * time.Second)
   ch <- "from service1"
} 

func service2(ch chan string) {
   time.Sleep(1 * time.Second)
   ch <- "from service2"
} 

func main() {

   ch1 := make(chan string)
   ch2 := make(chan string)
   go service1(ch1)
   go service2(ch2)
 
   select {       // 会发送阻塞
   case s1 := <-ch1:
       fmt.Println(s1)
   case s2 := <-ch2:
       fmt.Println(s2)
 }
 
}
//输出:
from service2

上面的函数执行到select语句时会发生阻塞,main主协程在等待一个case操作可执行,明显server2先准备好了写。

func server1(ch chan string) {
   //time.Sleep(2 * time.Second)
   ch <- "from service1"
}

func server2(ch chan string) {
   //time.Sleep(1 * time.Second)
   ch <- "from service2"
}

func main() {
   ch1 := make(chan string)
   ch2 := make(chan string)
   go server1(ch1)
   go server2(ch2)
 
   time.Sleep(2*time.Second)
 
   select {
   case s1 := <-ch1:
      fmt.Println(s1)
   case s2 := <-ch2:
      fmt.Println(s2)
   }
 
}

这种情况下会随机执行一个case

default case:

switch一样select也有default case,是的select语句不再阻塞,
如果其它信道没准备好,会直接执行default分支。

func server1(ch chan string) {
   ch <- "from service1"
}

func server2(ch chan string) {
   ch <- "from service2"
}

func main() {

   ch1 := make(chan string)
   ch2 := make(chan string)
   go server1(ch1)
   go server2(ch2)
   
   select {         // ch1 ch2 都还没有准备好,直接执行 default 分支 
   case s1 := <-ch1:
      fmt.Println(s1)
   case s2 := <-ch2:
      fmt.Println(s2)
   default:
     fmt.Println("no case ok")
 }
 
}
//输出:
no case ok

若在select前加一个延迟1s,则会随机执行case,不会执行default

nil channel:

若信道的默认值时nil,则不能对其进行读写操作。
func server1(ch chan string) {
 ch <- "from service1"
}

func main() {

   var ch chan string
   go server1(ch)
   select {
        case str := <-ch:
           fmt.Println(str)
   }
 
}
//输出:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
goroutine 18 [chan send (nil chan)]:

[select (no cases)] case 分支中如果信道是 nil,该分支就会被忽略。
就变成空 select{} 语句,阻塞主协程,开始调度 service1 协程,
在 nil 信道上操作,便报[chan send (nil chan)] 错误,可以使用default case避免。

空select:

func main(){
   select{}
}
//输出:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]

select语句会发生阻塞,直到case可以操作。但是空的select没有case分支,便会死锁
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值