Golang的select多路復用及channel使用操作
看到有個例子實現(xiàn)了一個類似于核彈發(fā)射裝置,在發(fā)射之前還是需要隨時能輸入終止發(fā)射。
這里就可以用到cahnnel 配合select 實現(xiàn)多路復用。
select的寫法用法有點像switch。但是和switch不同的是,select的一個case代表一個通信操作(在某個channel上進行發(fā)送或者接收)并且會包含一些語句組成的一個語句塊。現(xiàn)在讓我們來實現(xiàn)一下這個核彈發(fā)射器
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開始進行倒數(shù)計時。
申明一個int類型的 channel變量abort 用來做取消時候傳遞給select的消息信號量這個后面會介紹到。
申明一個int類型的 channel變量canLunch 用來做倒計時結束可以發(fā)射的信號量。 只有當?shù)箶?shù)結束,且canLunch有值后才能進行發(fā)射。
用一個goroutine開啟一個用于監(jiān)聽是否有停止發(fā)射信號的函數(shù)isAbort并且把申明好的channel變量傳入。
isAbort就干一件事情,監(jiān)聽是否有標準輸入輸入,如果有輸入我們默認是下達了發(fā)射停止的信號 需要向abort channel里面發(fā)送一個信號。這里我們會發(fā)射一個-1
用一個goroutine開啟一個用于倒數(shù)計時的函數(shù)commencingCountDown負責開始倒計時,這里重新申明了一個 TICK channel 每一秒倒數(shù)計時一下。并且在倒數(shù)計時完成之后向canLunch channel發(fā)送信號。
然后開始執(zhí)行select,select在沒有就緒的channel的時候會阻塞或者執(zhí)行指定的defualt,這里我沒有寫default所以他會阻塞監(jiān)聽兩個信號,一個是canLunch,一個是停止發(fā)送。只要收到任何一個信號后,執(zhí)行該信號后面的內(nèi)容
最后運行Lunch函數(shù)。
其實把思路理清楚,以并發(fā)的思考方式去思考這類問題感覺還是不會太亂。多加練習應該會變好。下面的文章應該會開始逐步開始從服務器和連接開始,實現(xiàn)一個im系統(tǒng)?;蛘咛砑痈嗟膶嵺`。
補充:golang 使用select完成超時
我就廢話不多說了,大家還是直接看代碼吧~
timeout := make(chan bool, 1)
go func() {
time.Sleep(1e9)
timeout <- true
} ()
select {
case <- ch:
//從ch中讀取數(shù)據(jù)
case <-timeout:
//ch一直沒有數(shù)據(jù)寫入,超時觸發(fā)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通道的數(shù)據(jù)"
time.Sleep(1e9 *3)
}
}
//在一定時間內(nèi)接收不到a的數(shù)據(jù)則超時
func getAchan(timeout time.Duration, a chan string) {
var after <-chan time.Time
loop:
after = time.After(timeout)
for{
fmt.Println("等待a中的數(shù)據(jù),10秒后沒有數(shù)據(jù)則超時")
select {
case x :=<- a:
fmt.Println(x)
goto loop
case <-after:
fmt.Println("timeout.")
return
}
}
}
func timing() {
//定時器,10秒鐘執(zhí)行一次
ticker := time.NewTicker(10 * time.Second)
for {
time := <-ticker.C
fmt.Println("定時器====>",time.String())
}
}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
相關文章
Go Resiliency庫中timeout實現(xiàn)原理及源碼解析
Go-Resiliency庫中的timeout是一種基于協(xié)程的超時機制,通過創(chuàng)建協(xié)程來執(zhí)行任務并設置超時時間,若任務執(zhí)行時間超時則中止協(xié)程并返回錯誤,需要詳細了解可以參考下文2023-05-05
Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究
這篇文章主要為大家介紹了Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01

