Go 語言 select 語句

Go 語言條件語句Go 語言條件語句

select是Go中的一個(gè)控制結(jié)構(gòu),類似于用于通信的switch語句。每個(gè)case必須是一個(gè)通信操作,要么是發(fā)送要么是接收。

select隨機(jī)執(zhí)行一個(gè)可運(yùn)行的case。如果沒有case可運(yùn)行,它將阻塞,直到有case可運(yùn)行。一個(gè)默認(rèn)的子句應(yīng)該總是可運(yùn)行的。

 這里的通信,可以簡單的理解為IO(輸入輸出),例如如下代碼

select {
    case <-ch1:
        // 如果從 ch1 信道成功接收數(shù)據(jù),則執(zhí)行該分支代碼
    case ch2 <- 1:
        // 如果成功向 ch2 信道成功發(fā)送數(shù)據(jù),則執(zhí)行該分支代碼
    default:
        // 如果上面都沒有成功,則進(jìn)入 default 分支處理流程
}

更多關(guān)于信道(channel)的內(nèi)容,可以前往channel詳解進(jìn)行了解。

語法

Go 編程語言中 select 語句的語法如下:

select {
    case communication clause  :
       statement(s)      
    case communication clause  :
       statement(s)
    /* 你可以定義任意數(shù)量的 case */
    default : /* 可選 */
       statement(s)
}

以下描述了 select 語句的語法:

  • 每個(gè)case都必須是一個(gè)通信
  • 所有channel表達(dá)式都會(huì)被求值
  • 所有被發(fā)送的表達(dá)式都會(huì)被求值
  • 如果任意某個(gè)通信可以進(jìn)行,它就執(zhí)行;其他被忽略。
  • 如果有多個(gè)case都可以運(yùn)行,Select會(huì)隨機(jī)公平地選出一個(gè)執(zhí)行。其他不會(huì)執(zhí)行。
    否則:
    1. 如果有default子句,則執(zhí)行該語句。
    2. 如果沒有default字句,select將阻塞,直到某個(gè)通信可以運(yùn)行;Go不會(huì)重新對channel或值進(jìn)行求值。

select的知識(shí)點(diǎn)小結(jié)如下:

  1. select語句只能用于信道的讀寫操作
  2. select中的case條件(非阻塞)是并發(fā)執(zhí)行的,select會(huì)選擇先操作成功的那個(gè)case條件去執(zhí)行,如果多個(gè)同時(shí)返回,則隨機(jī)選擇一個(gè)執(zhí)行,此時(shí)將無法保證執(zhí)行順序。對于阻塞的case語句會(huì)直到其中有信道可以操作,如果有多個(gè)信道可操作,會(huì)隨機(jī)選擇其中一個(gè) case 執(zhí)行
  3. 對于case條件語句中,如果存在信道值為nil的讀寫操作,則該分支將被忽略,可以理解為從select語句中刪除了這個(gè)case語句
  4. 如果有超時(shí)條件語句,判斷邏輯為如果在這個(gè)時(shí)間段內(nèi)一直沒有滿足條件的case,則執(zhí)行這個(gè)超時(shí)case。如果此段時(shí)間內(nèi)出現(xiàn)了可操作的case,則直接執(zhí)行這個(gè)case。一般用超時(shí)語句代替了default語句
  5. 對于空的select{},會(huì)引起死鎖
  6. 對于for中的select{}, 也有可能會(huì)引起cpu占用過高的問題

實(shí)例

package main

import "fmt"

func main() {
   var c1, c2, c3 chan int
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}

以上代碼執(zhí)行結(jié)果為:

no communication

Go 語言條件語句Go 語言條件語句