看到有個(gè)例子實(shí)現(xiàn)了一個(gè)類(lèi)似于核彈發(fā)射裝置,在發(fā)射之前還是需要隨時(shí)能輸入終止發(fā)射。
這里就可以用到cahnnel 配合select 實(shí)現(xiàn)多路復(fù)用。
select的寫(xiě)法用法有點(diǎn)像switch。但是和switch不同的是,select的一個(gè)case代表一個(gè)通信操作(在某個(gè)channel上進(jìn)行發(fā)送或者接收)并且會(huì)包含一些語(yǔ)句組成的一個(gè)語(yǔ)句塊。現(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類(lèi)型的 channel變量abort 用來(lái)做取消時(shí)候傳遞給select的消息信號(hào)量這個(gè)后面會(huì)介紹到。
申明一個(gè)int類(lèi)型的 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)有寫(xiě)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ā)的思考方式去思考這類(lèi)問(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í)
我就廢話(huà)不多說(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ù)寫(xiě)入,超時(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ò)誤或未考慮完全的地方,望不吝賜教。
您可能感興趣的文章:- Golang實(shí)現(xiàn)Directional Channel(定向通道)
- 詳解Golang中Channel的用法
- golang開(kāi)發(fā)中channel使用
- 基于golang channel實(shí)現(xiàn)的輕量級(jí)異步任務(wù)分發(fā)器示例代碼
- golang中for循環(huán)遍歷channel時(shí)需要注意的問(wèn)題詳解
- golang 函數(shù)返回chan類(lèi)型的操作