golang入門學習筆記(三)

作者: 一字馬胡
轉(zhuǎn)載標志 【2017-11-23】

更新日志

日期 更新內(nèi)容 備注
2017-11-23 新建文章 go語言入門學習筆記(三)

golang入門學習筆記系列

golang入門學習筆記(一)
golang入門學習筆記(二)

Select for golang

Go’s select lets you wait on multiple channel
operations. Combining goroutines and channels
with select is a powerful feature of Go.

go中的select類似于Linux中的select I/O,事件驅(qū)動,select等待在多個Channel反镇,當某個Channel的數(shù)據(jù)準備好了的時候就會執(zhí)行相應的動作,select保證會阻塞等待在一組Channel上她混,直到某個Channel完成(包括default語句)烈钞,下面是一個使用select的例子:


//  delay "delay" s then push the msg to channel "ch"
//   just test the select of goLang
//   difference msg and delay is needed
func selectFunc(msg string, delay int, ch chan string)  {
    if delay == 0 {
        delay = 1 // default delay 1s
    } else if delay > 5 {
        delay = 5 // the max delay time
    }

    time.Sleep(time.Second * time.Duration(delay))

    if msg == "" {
        ch <- "default msg from selectFunc";
    } else {
        ch <- msg
    }
}

    ch1 := make(chan string)
    ch2 := make(chan string)

    go selectFunc("msg from channel 1", 1, ch1)
    go selectFunc("msg from channel 2", 2, ch2)

    //at least revive 2 msg
    //
    for i := 0; i < 2; i ++ {
        select {
        case msg := <- ch1:
            log.Printf("%s\n", msg)
        case msg := <- ch2:
            log.Printf("%s\n", msg)
        }
    }

上面的例子展示了go語言中select的使用方法,它用于等待Channel的數(shù)據(jù)準備完成坤按,當有一個被select監(jiān)聽的Channel完成I/O之后就會進行相應的操作棵磷,上面的例子中沒有涉及default,default代表的意思是如果沒有Channel完成了I/O晋涣,那么就默認執(zhí)行default分支仪媒。上面的例子好像比較無聊,下面一個例子使用select來實現(xiàn)timeout的功能:


// using a goroutine to run this function.
// you can set the timeout value, then the function
// will wait some time, then set the channel to true
// means timeout
//
func timeoutFunc(timeout int, flag chan bool)  {
    if timeout == 0 {
        flag <- true // timeout now.
    }

    time.Sleep(time.Second * time.Duration(timeout))

    flag <- true
}

    ch1 := make(chan string)
    ch2 := make(chan string)
    timeoutCh := make(chan bool)

    go selectFunc("msg from channel 1", 1, ch1)
    go selectFunc("msg from channel 2", 4, ch2)
    go timeoutFunc(2, timeoutCh)

    //at least revive 2 msg
    //
    for i := 0; i < 2; i ++ {
        select {
        case <- timeoutCh:
            log.Printf("Time out !")
        case msg := <- ch1:
            log.Printf("%s\n", msg)
        case msg := <- ch2:
            log.Printf("%s\n", msg)
        }
    }
    

運行上面的代碼谢鹊,你將會發(fā)現(xiàn)輸出一條msg之后就會輸出超時了算吩,這還是非常有趣并且有用的。有些時候佃扼,我們需要顯示的關(guān)閉一個select偎巢,讓它不再阻塞監(jiān)聽它所關(guān)聯(lián)著的Channel,下面是一個使用close功能的select例子:


//check if we have more job to do.
//
func moreJobCheck(jobs chan int, done chan bool)  {
    for {
        j , more := <- jobs
        if more {
            log.Printf("Receive job: %d\n", j)
        } else {
            done <- true
            log.Printf("No more Jobs\n")
            return
        }
    }
}


    jobCh := make(chan int)
    done := make(chan  bool)

    go moreJobCheck(jobCh, done)

    for i := 0; i < 4; i ++ {
        jobCh <- i
    }

    //close the job.
    close(jobCh)

    <- done
    

Timers for golang

We often want to execute Go code at some point in
the future, or repeatedly at some interval.
Go’s built-in timer and ticker features
make both of these tasks easy

Timers represent a single event in the future.
You tell the timer how long you want to wait,
and it provides a channel that will be notified at that time

If you just wanted to wait, you could have
used time.Sleep. One reason a timer may be
useful is that you can cancel the timer before it expires.

下面是關(guān)于timer的一個例子兼耀,上面提到压昼,如果你僅僅是想要休眠一段時間,使用time.Sleep就可以了瘤运,但是使用timer的一個原因是你可以在timer超時之前取消它窍霞。


    timeout1 := time.NewTimer(time.Second * time.Duration(1)) // timeout := 1s
    timeout2 := time.NewTimer(time.Second * time.Duration(2)) // timeout := 2s

    <- timeout1.C

    log.Printf("timeout1 expired")

    go func() {
        <- timeout2.C
        log.Printf("timeout2 expired")
    }()

    timeout2Stop := timeout2.Stop() // stop the timer

    if timeout2Stop {
        log.Printf("timeout2 was stoped")
    }

tickers for golang

Timers are for when you want to do something
once in the future - tickers are for when
you want to do something repeatedly at regular intervals.

tickers和timer的區(qū)別在于,timer類似于計時器拯坟,會等待一段時間但金,而ticker類似于定時器,會周期性的超時郁季,下面是一個使用ticker的例子:


    ticker := time.NewTicker(time.Second * time.Duration(1)) // schedule 1s

    go func() {
        for t := range ticker.C {
            log.Printf("Tocker at:%s\n", t)
        }
    } ()

    time.Sleep(time.Second * time.Duration(2))

    ticker.Stop()

Worker Pools

到目前為止已經(jīng)學習了goroutine冷溃、Channel、select梦裂,那如何使用這些組件來實現(xiàn)Worker Pools呢似枕?下面是一個實現(xiàn):


//simulate the work,receive job ob the jobs channel,
// then do the job and get the result and send the
// corresponding results on results.
func wokrer(jobId int, jobs <- chan int, result chan <- int)  {
    for job := range jobs {
        log.Printf("worker #%d start to do the job #%d", jobId, job)
        time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
        log.Printf("worker #%d finished to do the job #%d", jobId, job)

        //corresponding results on results.
        result <- job * jobId
    }
}

    jobs := make(chan int, 10)
    result := make(chan int, 10)

    for w := 1; w < 5; w ++ {
        go wokrer(w, jobs, result)
    }

    for j := 1; j < 10; j ++ {
        jobs <- j
    }

    close(jobs)

    for r := 1; r < 5; r ++ {
        <- result
    }
    

上面的例子簡單實現(xiàn)了一個worker pool,其實和java中的線程池是類似的年柠,個中原委凿歼,還得自己慢慢體會啊彪杉!

Rate Limiting

Rate limiting is an important mechanism for controlling resource
utilization and maintaining quality of service. Go elegantly
supports rate limiting with >goroutines, channels, and tickers

下面是實現(xiàn)Rate Limiting的一個小例子:


    mockRequest := make(chan int, 10)

    for i := 1; i <= 10; i ++ {
        mockRequest <- i
    }

    close(mockRequest)

    limiter := time.Tick(time.Millisecond * time.Duration( 100 )) // 100 ms

    for request := range mockRequest {
        <- limiter
        log.Printf("Request inCome:%d At %s", request, time.Now())
    }

limiter的職責就是做限流毅往,每過100ms再嘗試去獲取一個request來執(zhí)行牵咙,這樣就可以保護我們的server可以穩(wěn)定運行了派近。但是這個例子中使用了timer來做Rate Limiting,下面的例子使用ticker來實現(xiàn)更復雜的Rate Limiting:


    burstyLimiter := make(chan time.Time, 5)

    for i := 0; i < 5; i ++ {
        burstyLimiter <- time.Now()
    }

    go func() {
        for t := range time.Tick(time.Millisecond * time.Duration(100)) {
            burstyLimiter <- t
        }
    } ()

    burstyRequest := make(chan int, 10)
    for i := 1; i <= 10; i ++ {
        burstyRequest <- i
    }

    close(burstyRequest)

    for request := range burstyRequest {
        <- burstyLimiter
        log.Printf("Request inCome: %d At %s", request, time.Now())
    }

上面的例子感覺就優(yōu)點復雜了洁桌,我們使用了5個ticker來實現(xiàn)Rate Limiting渴丸,每個Rate Limiting過100ms接收一個請求來處理,當然Rate Limiting的需求是否那么緊迫還不得而知,我們總是希望我們的服務能跑得越快越好谱轨,QPS越高越好戒幔,但是同時我們也需要考慮是否需要做一些Rate Limiting的工作,這一點也需要仔細體會才能得到結(jié)論啊土童,但是golang提供了實現(xiàn)Rate Limiting的思路诗茎,日后可以借鑒一下。

文/一字馬胡
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末献汗,一起剝皮案震驚了整個濱河市敢订,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罢吃,老刑警劉巖楚午,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異尿招,居然都是意外死亡矾柜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門就谜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怪蔑,“玉大人,你說我怎么就攤上這事丧荐∫牵” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵篮奄,是天一觀的道長捆愁。 經(jīng)常有香客問我,道長窟却,這世上最難降的妖魔是什么昼丑? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮夸赫,結(jié)果婚禮上菩帝,老公的妹妹穿的比我還像新娘。我一直安慰自己茬腿,他們只是感情好呼奢,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著切平,像睡著了一般握础。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悴品,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天禀综,我揣著相機與錄音简烘,去河邊找鬼。 笑死定枷,一個胖子當著我的面吹牛孤澎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播欠窒,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼覆旭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了岖妄?” 一聲冷哼從身側(cè)響起姐扮,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衣吠,沒想到半個月后茶敏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡缚俏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年惊搏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忧换。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恬惯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亚茬,到底是詐尸還是另有隱情酪耳,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布刹缝,位于F島的核電站碗暗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏梢夯。R本人自食惡果不足惜言疗,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颂砸。 院中可真熱鬧噪奄,春花似錦、人聲如沸人乓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽色罚。三九已至碰缔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間保屯,已是汗流浹背手负。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姑尺,地道東北人竟终。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像切蟋,于是被迫代替她去往敵國和親统捶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

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