go example之旅(下)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Introduce

這是來自於go by example的例子,花了幾天的時間寫完了這些例子,感覺對我的協助很大,對於初學者來說,我的建議還是先找本go的書從頭到尾看一下,然後再來看這些例子,每個例子都手敲一遍,對你的協助還是很大的。在敲這些例子的過程中,有一些疑問,也有一些知識的擴充,因此總結了本文。

time和channel

golang的time package帶有定時器的功能,而定時器和channel完美融合,建立一個定時器會返回一個channel,在定時器到期之前讀這個channel是阻塞的,直到定時時間到達這個channel就會變成可讀的。

func main() {    //建立了一個定時器,2秒後會發送事件到timer1.C channel    timer1 := time.NewTimer(time.Second * 2)    //等待定時器到期    data := <-timer1.C          //接收到的資料 2016-07-16 15:24:19.337701998 +0800 CST    fmt.Println("Timer 1 expired")    fmt.Println("Timer 1 expired",data)    timer2 := time.NewTimer(time.Second)    go func() {        <- timer2.C        fmt.Println("Timer 2 expired")    }()    //關閉定時器    stop2 := timer2.Stop()    if stop2 {        fmt.Println("Timer 2 stopped")    }}

time package除了具有定時器的功能外,還有一個Ticker,Ticker同樣也是和channel完美融合的一個功能,建立一個Ticker會返回channel
通過range這個channel。來表示每次interval的到來。再結合go的協程就很容易實現一個定時任務的功能。

func main() {    //建立了定時器,每time.Millisecond * 500就產生事件,發送到chnanel    ticker := time.NewTicker(time.Millisecond * 500)    go func() {        for t := range ticker.C {            fmt.Println("Tick at",t)        }    }()    //睡上一段事件,然後關閉    time.Sleep(time.Millisecond * 1600)    ticker.Stop()    fmt.Println("Ticker stopped")}

goroutines和work pool

goroutines結合channel很容易就可以實現一個work pool,開上N個goroutines,然後這N個goroutines共同去讀channel,讀到channel
就去執行相應的工作,然後結果通過另外一個channel傳出來即可,模型很簡單。用go實現起來還是很容易的。

func worker(id int,jobs <-chan int,result chan<- int) {    for j := range jobs {        fmt.Println("worker",id,"processing job",j)        time.Sleep(time.Second)        result <- j * 2    }}func main() {    jobs := make(chan int,100)    results := make(chan int,100)    //啟動三個worker    for w := 1; w <= 3; w++ {        go worker(w,jobs,results)    }    //迴圈9次,發送任務    for j := 1; j <= 9;j++ {        jobs <- j    }    close(jobs)    //迴圈得到結果    for a := 1; a <= 9; a++ {        <-results    }}

rate limiting與channel

限速這是一個用於控制資源使用率和保證服務品質的一種機制,golang通過goroutines,channel還有tickers優雅的支援了這個機制。比如處理web請求的限速,每接收一個請求就先讀取一個tick,這個tick每隔固定時間才可讀,這樣就可以實現限速的功能。

func main() {    requests := make(chan int,5)    //發送五條訊息    for i := 1; i <= 5;i++ {        requests <- i    }    close(requests)    //建立了定時器,然後遍曆channel,列印資訊    limiter := time.Tick(time.Millisecond * 200)    for req := range requests {        <-limiter   //每隔time.Millisecond * 200,起到了限速的作用        fmt.Println("requests",req,time.Now())    }}

但是上面的限速存在一個問題,就是並發數只有1,如果可以在擁有固定的並發數的情況下限速呢?,這就需要藉助channel的buffer功能了。上面的time.Tick返回的channel是沒有buffer的,所以一次只能處理一個請求,如果這個channel是有buffer的,比如這個buffer的大小是N那麼可以同時並發接收N個請求,想處理第N+1個請求就需要等待固定時間才可以。

func main() {    //建立了另外一個time.Time類似的channel    burstyLimiter := make(chan time.Time,3)    //發送三個    for i := 0; i < 3; i++ {        burstyLimiter <- time.Now()    }    go func() {        for t := range time.Tick(time.Millisecond * 200) {            burstyLimiter <- t //每200 * time.Millisecond 就發送一個事件到burstyLimiter        }    }()    burstyRequests := make(chan int,5)    for i := 1; i <= 5; i++ {        burstyRequests <- i //發送五個資料    }    close(burstyRequests)    for req := range burstyRequests { //現在開始限速讀取        <-burstyLimiter//在讀前三個的時候是不會阻塞的,直到讀取第四個的 時候才開始通過Limiter限速        fmt.Println("request",req,time.Now())    }}

自訂sort和Interface

golang的sort package內建排序的功能,但是如果要對使用者自己定義的資料結構進行排序這就不好半了,在C++中要求使用者對關係運算子重載即可在golang中則需要和interface完美融合,只要使用者實現Len,Less,Swap三個介面即可,就是這麼簡單。

package mainimport "fmt"import "sort"//string slice的別名,給這個別名struct 添加方法type ByLength []stringfunc (s ByLength) Len() int {    return len(s)}func (s ByLength) Swap(i,j int) {    s[i],s[j] = s[j],s[i]}func (s ByLength) Less(i,j int) bool {    return len(s[i]) < len(s[j])}//sort介面需要實現 Swap Less和len即可func main() {    fruits := []string{"peach","banana","kiwi"}    sort.Sort(ByLength(fruits))    fmt.Println(fruits)}

signal和channel

golang再一次將unix上的signals和channel結合了起來,unix上通過給訊號註冊處理函數來完成訊號處理,在golang中,通過把訊號和channel關聯起來,當有訊號到來channel就可讀了。返回的結果就是signal的號碼。

import "fmt"import "os"import "os/signal"import "syscall"func main() {    //os.Signal類型的chn    sigs := make(chan os.Signal,1)    done := make(chan bool,1)    //通過Norify來註冊訊號,    signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM)  //將SIGINT和SIGTERM和sigs channel結合起來    //協成來收集訊號,然後發送done chan來表示完成    go func() {        sig :=  <-sigs        fmt.Println()        fmt.Println(sig)        done <- true    }()    fmt.Println("awaiting signal")    <-done    fmt.Println("exiting")}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.