Go 語言編程實例(二)

select 實例

Go 語言選擇(select)可以等待多個通道操作。將 goroutinechannelselect 結(jié)合是 Go 語言的一個強大功能沽瘦。看起來可能和 switch 相似,但是并不是史飞。

對于這個示例猫妙,將選擇兩個通道瓷翻。

每個通道將在一段時間后開始接收值,以模擬阻塞在并發(fā) goroutines 中執(zhí)行 RPC 操作割坠。我們將使用 select 同時等待這兩個值齐帚,在每個值達到時打印它們。

執(zhí)行實例程序得到的值是 one 彼哼, 然后是 two 对妄。注意,總執(zhí)行時間只有 1-2 秒 Sleeps 同時執(zhí)行敢朱。

package main
import (
    "fmt"
    "time"
)

func main(){
    // channel
    c1 := make (chan string)
    c2 := make (chan string)

    go func(){
        time.Sleep(time.Second * 1)
        c1 <- "ONE"
    }()

    go func(){
        time.Sleep(time.Second * 2)
        c2 <- "TWO"
    }()

    for i := 0 ; i < 2 ; i ++ {
        select {
            case msg1 := <-c1:
            fmt.Println("received~one",msg1)
            case msg2 := <-c2:
            fmt.Println("received~two",msg2)
        }
    }
}

超時(timeouts)實例

超時對于連接到外部資源或在不需要綁定執(zhí)行時間的程序很重要剪菱。在 Go 編程中由于使用了通道和選擇 (select),實現(xiàn)超時是很容易和優(yōu)雅的拴签。

在這個示例中孝常,假設(shè)正在執(zhí)行一個外部調(diào)用,2秒后在通道 C1 上返回其結(jié)果篓吁。

這里是 select 實現(xiàn)超時茫因。res := <-c1 等待結(jié)果和 <-Time 。等待在超時 1 秒后發(fā)送一個值杖剪。由于選擇繼續(xù)準備好第一個接收冻押,如果超時超過允許的 1 秒,則將按照超時情況處理盛嘿。

如果允許更長的超時洛巢,如: 3s ,那么從 c2 的接收將成功次兆,這里將會打印稿茉。

運行此程序顯示第一個操作超時和第二個操作超時。

使用此選擇超時模式需要通過通道傳達結(jié)果芥炭。這是一個好主意漓库,因為其他重要的 Go 功能是基于渠道和 Select。現(xiàn)在看看下面的兩個例子:計時器和ticker 园蝠。

package main
import (
    "time"
    "fmt" 
)
func main(){
    c1 := make(chan string,1)
    go func(){
        time.Sleep(time.Second *2)
        c1 <- "result 1"
    }()
    select {
        case res := <-c1:
        fmt.Println(res)
        case <-time.After(time.Second *1):
        fmt.Println("timeout 1")
    }
    c2 := make(chan string , 1)
    go func() {
        time.Sleep(time.Second * 2)
        c2 <- "result 2"
    }()
    select {
        case res := <-c2:
        fmt.Println(res)
        case <-time.After(time.Second *3):
        fmt.Println("timeout2")
    }
}

非阻塞通道操作實例

通道的基本發(fā)送和接受都阻塞渺蒿。但是,可以使用 selectdefault 子句來實現(xiàn)非阻塞發(fā)送彪薛,接收茂装,甚至非阻塞多路選擇( select )怠蹂。

這里會是一個非阻塞接收。如果消息上有可用的值少态,則選擇將使用該值的 <-message 城侧。如果不是,它會立即采取默認情況彼妻。

可以使用多個上面的默認子句來實現(xiàn)多路非阻塞選擇(select)嫌佑。這里嘗試對消息(message) 和信號(signals) 的非阻塞接收。

package main

import (
    "fmt"
    "time"
)

func main(){
    messages := make(chan string)
    signals  := make(chan bool)

    go func() {
        messages <- "test"
    }()

    time.Sleep(time.Second * 1)
    select{
        case msg := <-messages:
            fmt.Println("Received message",msg)
        default:
            fmt.Println("no message received")
    }

    msg := "hi"

    select {
        case messages<-msg:
            fmt.Println("sent message",msg)
        default:
            fmt.Println("no message sent")
    }

    select {
        case msg := <- messages:
            fmt.Println("received message",msg)
        case sig := <-signals:
            fmt.Println("received signals",sig)
        default:
            fmt.Println("no activity")
    }
}

go 關(guān)閉通道實例

關(guān)閉通道表示不會再發(fā)送值澳骤。這對于將完成通訊到通道的接收器是很有用的歧强。

在這個例子中,我們將使用一個作業(yè)通道來完成從 main goroutine 到 worker goroutine 的工作为肮。當沒有更多的工作時,則將關(guān)閉工作通道肤京。

這里是工作程序 goroutine颊艳。它反復(fù)從j的工作接收 more := <- jobs 。在這種特殊的 2 值形式的接收中忘分。如果作業(yè)已關(guān)閉并且接受到的通道中的所有值棋枕,則 more 的值將為 false。當已經(jīng)完成了所有的工作時妒峦,使用這個通知重斑。

這會通過作業(yè)通道向工作線程發(fā)送 3 個作業(yè),然后關(guān)閉它肯骇。

package main

import "fmt"

func main(){
    jobs := make(chan int,5)
    done := make(chan bool)

    go func() {
        for {
            j , more := <- jobs
            if more{
                fmt.Println("received job",j)
            }else {
                fmt.Println("received all jobs")
                done <- true
                return
            }
        }
    }()

    for j:=1 ; j<= 3 ; j++{
        jobs <- j
        fmt.Println("send job",j)
    }

    //關(guān)閉通道
    close(jobs)
    fmt.Println("send all jobs")

    //
    fmt.Println(<-done)
}

以上例程中實際輸出的時候遇到輸出為以下樣子:

"D:\Program\Gogland 172.3757.2\bin\runnerw.exe" C:\Go\bin\go.exe run C:/Go/MyGo/src/lesson5_select/close_chan.go
send job 1
send job 2
received job 1
received job 2
received job 3
send job 3
send all jobs
received all jobs
true

個人猜想是因為 goroutine 中執(zhí)行的線程調(diào)度的時候快于 主要 routine窥浪。所以出現(xiàn)以上輸出,但是就是實際執(zhí)行過程的時候一定是接收到發(fā)送過后再輸出笛丙。

go 通道范圍實例

在前面的例子中漾脂,我們已經(jīng)看到了 forrange 語句如何為基于數(shù)據(jù)結(jié)構(gòu)提供迭代。還可以使用此語法對從通道接收的值進行迭代胚鸯。

此范圍在從隊列中接收到的每個元素上進行迭代骨稿。因為關(guān)閉了上面的通道,迭代在接收到 2 個元素后終止姜钳。

這個示例還可以關(guān)閉非空信道坦冠,但仍接收剩余值。

package main

import "fmt"

func main(){
    //存放兩個值在通道中

    queue := make(chan string,2)
    queue <- "one"
    queue <- "two"

    close(queue)

    for elem:=range queue{
        fmt.Println(elem)
    }
}

輸出結(jié)果如下:

"D:\Program\Gogland 172.3757.2\bin\runnerw.exe" C:\Go\bin\go.exe run C:/Go/MyGo/src/lesson5_select/chan_range.go
one
two

go 計時器實例

我們經(jīng)常想在將來某個時間點執(zhí)行Go 代碼哥桥,或者在某個時間間隔重復(fù)執(zhí)行辙浑。 Go 內(nèi)置計時器和自動接收器功能使這兩項任務(wù)變得容易。我們先看看定時器泰讽,然后再看看行情例衍。

定時器代表未來的一個事件昔期。可告訴定時器您想要等待多長時間佛玄,它提供一個通道硼一,得到通知的時候執(zhí)行相應(yīng)程序。在這個示例中梦抢,計時器將等待2 秒鐘般贼。

<-timer1.C 阻塞定時器的通道 C ,直到它發(fā)送一個指示定時器超時的值奥吩。

如果只是想等待哼蛆,可以使用 time.Sleep 。定時器可能起作用的一個原因是在定時器到期之前取消定時器霞赫。

第一個定時器將在啟動程序后 2s 后過期腮介,但第二個定時器應(yīng)該在它到期之前停止。

package main

import (
    "time"
    "fmt"
)

func main(){
    timer1 := time.NewTimer(time.Second * 2)

    <-timer1.C

    fmt.Println("Timer 1 expired")

    timer2 := time.NewTimer(time.Second)

    go func() {
        <- timer2.C
        fmt.Println("Timer 2 expired")
    }()

    stop2 := timer2.Stop()

    if stop2{
        fmt.Println("Timer 2 stoped")
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末端衰,一起剝皮案震驚了整個濱河市叠洗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旅东,老刑警劉巖灭抑,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抵代,居然都是意外死亡腾节,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門荤牍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來案腺,“玉大人,你說我怎么就攤上這事参淫【群” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵涎才,是天一觀的道長鞋既。 經(jīng)常有香客問我,道長耍铜,這世上最難降的妖魔是什么邑闺? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮棕兼,結(jié)果婚禮上陡舅,老公的妹妹穿的比我還像新娘。我一直安慰自己伴挚,他們只是感情好靶衍,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布灾炭。 她就那樣靜靜地躺著,像睡著了一般颅眶。 火紅的嫁衣襯著肌膚如雪蜈出。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天涛酗,我揣著相機與錄音铡原,去河邊找鬼。 笑死商叹,一個胖子當著我的面吹牛燕刻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剖笙,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼卵洗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枯途?” 一聲冷哼從身側(cè)響起忌怎,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酪夷,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孽惰,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡晚岭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了勋功。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坦报。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖狂鞋,靈堂內(nèi)的尸體忽然破棺而出片择,到底是詐尸還是另有隱情,我是刑警寧澤骚揍,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布字管,位于F島的核電站,受9級特大地震影響信不,放射性物質(zhì)發(fā)生泄漏嘲叔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一抽活、第九天 我趴在偏房一處隱蔽的房頂上張望硫戈。 院中可真熱鬧,春花似錦下硕、人聲如沸丁逝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霜幼。三九已至嫩码,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辛掠,已是汗流浹背谢谦。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萝衩,地道東北人回挽。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像猩谊,于是被迫代替她去往敵國和親千劈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理牌捷,服務(wù)發(fā)現(xiàn)墙牌,斷路器,智...
    卡卡羅2017閱讀 134,665評論 18 139
  • Goroutine是Go里的一種輕量級線程——協(xié)程暗甥。相對線程喜滨,協(xié)程的優(yōu)勢就在于它非常輕量級,進行上下文切換的代價非...
    witchiman閱讀 4,837評論 0 9
  • Go的內(nèi)存模型 看完這篇文章你會明白 一個Go程序在啟動時的執(zhí)行順序 并發(fā)的執(zhí)行順序 并發(fā)環(huán)境下如何保證數(shù)據(jù)的同步...
    初級賽亞人閱讀 2,855評論 0 2
  • 微信撤防,改界面了虽风,標志著從“人類起源”走向“華夏文明”; 而朋友圈寄月,經(jīng)過好幾輪的洗禮辜膝,也從泛泛溝通演變到了精細化經(jīng)營...
    茍秋閱讀 473評論 0 0
  • 漸行漸遠 慢慢消失在人海 也許是你們的背影太迷人 看的我模糊了雙眼 我的雙眼全是你們的背影 它已深深刻在我心里 鳥...
    路上過客閱讀 481評論 17 14