Golang的select多路復(fù)用及channel使用操作
看到有個(gè)例子實(shí)現(xiàn)了一個(gè)類似于核彈發(fā)射裝置,在發(fā)射之前還是需要隨時(shí)能輸入終止發(fā)射。
這里就可以用到cahnnel 配合select 實(shí)現(xiàn)多路復(fù)用。
select的寫法用法有點(diǎn)像switch。但是和switch不同的是,select的一個(gè)case代表一個(gè)通信操作(在某個(gè)channel上進(jìn)行發(fā)送或者接收)并且會(huì)包含一些語(yǔ)句組成的一個(gè)語(yǔ)句塊?,F(xiàn)在讓我們來(lái)實(shí)現(xiàn)一下這個(gè)核彈發(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() }
首先打印了一個(gè)commencing countdown開(kāi)始進(jìn)行倒數(shù)計(jì)時(shí)。
申明一個(gè)int類型的 channel變量abort 用來(lái)做取消時(shí)候傳遞給select的消息信號(hào)量這個(gè)后面會(huì)介紹到。
申明一個(gè)int類型的 channel變量canLunch 用來(lái)做倒計(jì)時(shí)結(jié)束可以發(fā)射的信號(hào)量。 只有當(dāng)?shù)箶?shù)結(jié)束,且canLunch有值后才能進(jìn)行發(fā)射。
用一個(gè)goroutine開(kāi)啟一個(gè)用于監(jiān)聽(tīng)是否有停止發(fā)射信號(hào)的函數(shù)isAbort并且把申明好的channel變量傳入。
isAbort就干一件事情,監(jiān)聽(tīng)是否有標(biāo)準(zhǔn)輸入輸入,如果有輸入我們默認(rèn)是下達(dá)了發(fā)射停止的信號(hào) 需要向abort channel里面發(fā)送一個(gè)信號(hào)。這里我們會(huì)發(fā)射一個(gè)-1
用一個(gè)goroutine開(kāi)啟一個(gè)用于倒數(shù)計(jì)時(shí)的函數(shù)commencingCountDown負(fù)責(zé)開(kāi)始倒計(jì)時(shí),這里重新申明了一個(gè) TICK channel 每一秒倒數(shù)計(jì)時(shí)一下。并且在倒數(shù)計(jì)時(shí)完成之后向canLunch channel發(fā)送信號(hào)。
然后開(kāi)始執(zhí)行select,select在沒(méi)有就緒的channel的時(shí)候會(huì)阻塞或者執(zhí)行指定的defualt,這里我沒(méi)有寫default所以他會(huì)阻塞監(jiān)聽(tīng)兩個(gè)信號(hào),一個(gè)是canLunch,一個(gè)是停止發(fā)送。只要收到任何一個(gè)信號(hào)后,執(zhí)行該信號(hào)后面的內(nèi)容
最后運(yùn)行Lunch函數(shù)。
其實(shí)把思路理清楚,以并發(fā)的思考方式去思考這類問(wèn)題感覺(jué)還是不會(huì)太亂。多加練習(xí)應(yīng)該會(huì)變好。下面的文章應(yīng)該會(huì)開(kāi)始逐步開(kāi)始從服務(wù)器和連接開(kāi)始,實(shí)現(xiàn)一個(gè)im系統(tǒng)?;蛘咛砑痈嗟膶?shí)踐。
補(bǔ)充:golang 使用select完成超時(shí)
我就廢話不多說(shuō)了,大家還是直接看代碼吧~
timeout := make(chan bool, 1) go func() { time.Sleep(1e9) timeout <- true } () select { case <- ch: //從ch中讀取數(shù)據(jù) case <-timeout: //ch一直沒(méi)有數(shù)據(jù)寫入,超時(shí)觸發(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) } } //在一定時(shí)間內(nèi)接收不到a的數(shù)據(jù)則超時(shí) 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秒后沒(méi)有數(shù)據(jù)則超時(shí)") select { case x :=<- a: fmt.Println(x) goto loop case <-after: fmt.Println("timeout.") return } } } func timing() { //定時(shí)器,10秒鐘執(zhí)行一次 ticker := time.NewTicker(10 * time.Second) for { time := <-ticker.C fmt.Println("定時(shí)器====>",time.String()) } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Go Resiliency庫(kù)中timeout實(shí)現(xiàn)原理及源碼解析
Go-Resiliency庫(kù)中的timeout是一種基于協(xié)程的超時(shí)機(jī)制,通過(guò)創(chuàng)建協(xié)程來(lái)執(zhí)行任務(wù)并設(shè)置超時(shí)時(shí)間,若任務(wù)執(zhí)行時(shí)間超時(shí)則中止協(xié)程并返回錯(cuò)誤,需要詳細(xì)了解可以參考下文2023-05-05Golang實(shí)現(xiàn)自己的Redis(有序集合跳表)實(shí)例探究
這篇文章主要為大家介紹了Golang實(shí)現(xiàn)自己的Redis(有序集合跳表)實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01GO語(yǔ)言支付寶沙箱對(duì)接的實(shí)現(xiàn)
本文介紹了如何使用GO語(yǔ)言對(duì)接支付寶沙箱環(huán)境,包括秘鑰生成、SDK安裝和代碼實(shí)現(xiàn)等步驟,詳細(xì)內(nèi)容涵蓋了從秘鑰生成到前端代碼的每個(gè)階段,為開(kāi)發(fā)者提供了一條清晰的指引2024-09-09go貨幣計(jì)算時(shí)如何避免浮點(diǎn)數(shù)精度問(wèn)題
在開(kāi)發(fā)的初始階段,我們經(jīng)常會(huì)遇到“浮點(diǎn)數(shù)精度”和“貨幣值表示”的問(wèn)題,那么在golang中如何避免這一方面的問(wèn)題呢,下面就跟隨小編一起來(lái)學(xué)習(xí)一下吧2024-02-02