1. 程式人生 > 程式設計 >Golang的select多路複用及channel使用操作

Golang的select多路複用及channel使用操作

看到有個例子實現了一個類似於核彈發射裝置,在發射之前還是需要隨時能輸入終止發射。

這裡就可以用到cahnnel 配合select 實現多路複用。

select的寫法用法有點像switch。但是和switch不同的是,select的一個case代表一個通訊操作(在某個channel上進行傳送或者接收)並且會包含一些語句組成的一個語句塊。現在讓我們來實現一下這個核彈發射器

package main
import (
 "fmt"
 "time"
 "os"
)
func launch() {
 fmt.Println("nuclear launch detected")
}
func commencingCountDown(canLunch chan int) {
 c := time.Tick(1 * time.Second)
 for countDown := 20; countDown > 0; countDown-- {
  fmt.Println(countDown)
  <- c
 }
 canLunch <- -1
}
func isAbort(abort chan int) {
 os.Stdin.Read(make([]byte,1))
 abort <- -1
}
func main() {
 fmt.Println("Commencing coutdown")
 abort := make(chan int)
 canLunch := make(chan int)
 go isAbort(abort)
 go commencingCountDown(canLunch)
 select {
 case <- canLunch:
 case <- abort:
  fmt.Println("Launch aborted!")
  return
 }
 launch()
}

首先列印了一個commencing countdown開始進行倒數計時。

申明一個int型別的 channel變數abort 用來做取消時候傳遞給select的訊息訊號量這個後面會介紹到。

申明一個int型別的 channel變數canLunch 用來做倒計時結束可以發射的訊號量。 只有當倒數結束,且canLunch有值後才能進行發射。

用一個goroutine開啟一個用於監聽是否有停止發射訊號的函式isAbort並且把申明好的channel變數傳入。

isAbort就幹一件事情,監聽是否有標準輸入輸入,如果有輸入我們預設是下達了發射停止的訊號 需要向abort channel裡面傳送一個訊號。這裡我們會發射一個-1

用一個goroutine開啟一個用於倒數計時的函式commencingCountDown負責開始倒計時,這裡重新申明瞭一個 TICK channel 每一秒倒數計時一下。並且在倒數計時完成之後向canLunch channel傳送訊號。

然後開始執行select,select在沒有就緒的channel的時候會阻塞或者執行指定的defualt,這裡我沒有寫default所以他會阻塞監聽兩個訊號,一個是canLunch,一個是停止傳送。只要收到任何一個訊號後,執行該訊號後面的內容

最後執行Lunch函式。

其實把思路理清楚,以併發的思考方式去思考這類問題感覺還是不會太亂。多加練習應該會變好。下面的文章應該會開始逐步開始從伺服器和連線開始,實現一個im系統。或者新增更多的實踐。

補充:golang 使用select完成超時

我就廢話不多說了,大家還是直接看程式碼吧~

timeout := make(chan bool,1)
go func() {
 time.Sleep(1e9)
 timeout <- true
} ()
 
select {
 case <- ch:
  //從ch中讀取資料
 case <-timeout:
  //ch一直沒有資料寫入,超時觸發timeout
}
func main() {
 var a chan string
 a =make(chan string)
 go sendDataTo(a)
 go timing()
 getAchan(10*time.Second,a) 
}
 
func sendDataTo(a chan string) {
 for {
   a <- "我是a通道的資料"
  time.Sleep(1e9 *3)
 }
}
 
//在一定時間內接收不到a的資料則超時
func getAchan(timeout time.Duration,a chan string) {
 var after <-chan time.Time
 loop:
 after = time.After(timeout)
 for{
  fmt.Println("等待a中的資料,10秒後沒有資料則超時")
  select {
  case x :=<- a:
   fmt.Println(x)
   goto loop
  case <-after:
   fmt.Println("timeout.")
   return
  }
 }
}
func timing() {
 //定時器,10秒鐘執行一次
 ticker := time.NewTicker(10 * time.Second)
 for {
  time := <-ticker.C
  fmt.Println("定時器====>",time.String())
 }
} 

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方,望不吝賜教。