關於Goroutine Channel Select 的用法和理解

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

聲明

轉載請註明本文地址,感謝 :)

瞭解進程、線程、協程

本文不詳細解釋這三個名詞的意思,下面有一篇文章,不懂的同學可以參考看看。

  • http://www.cnblogs.com/work115/p/5620272.html

Goroutine的使用

  • Goroutine 奉行通過通訊來共用記憶體,而不是共用記憶體來通訊
  • 使用goroutine很簡單,只需要用到一個關鍵字go,我們用一段代碼來樣本一下如何使用go關鍵字
12345678910111213
package mainimport ("fmt")func main() {go Goroutine()}func Goroutine() {fmt.Println("Goroutine")}

沒有輸出?

  • 執行了上面的代碼後,你會發現,什麼都沒有輸出,那麼是什麼問題呢?
  • 因為我們當前的程式,只是一個單線程的程式,main函數只要執行完畢後,就不會再管其他線程在做什麼事情了,程式自動結束。 然後我們想到了一個辦法,加一個sleep函數,讓main函數等待Goroutine函數執行完畢後再退出。

  • 更改後的代碼如下:

123456789101112131415
package mainimport ("fmt""time")func main() {go Goroutine()time.Sleep(3 * time.Second)}func Goroutine() {fmt.Println("Goroutine")}
  • 不出所料,程式成功列印出了“Goroutine”字串。

引入Channel

  • 通過上面的實驗,我們成功地用Goroutine,並列印出了一句話。現在問題來了,這個並不是我們想要的。為什嗎?如果我的Goroutine函數裡的代碼需要執行10s、20s甚至更多的時候,怎麼辦?難道還是繼續Sleep更多的秒數嗎?
  • 我們需要的是,當Goroutine函數執行完畢的時候,自動通知main函數。所以這裡我們就引出了channel

建立方式

  • channel使用make建立

    • chann := make(chan bool)
  • 往channel中傳入資料

    • chann <- true
  • 輸出channel中的資料

    • <- chann
  • 接著我們改進上面使用Sleep方式的代碼,換成使用channel的版本

  • 代碼如下:
12345678910111213141516
package mainimport ("fmt")func main() {chann := make(chan bool)go func() {fmt.Println("Goroutine")chann <- true}()<- chann}
  • 如果運行以上的程式碼片段後,你成功輸出了Goroutine,那麼說明我們的寫法是沒錯的。現在我們來理解一下這段代碼的意思,我們看看匿名函數外面的<-chann,這實際上是起到了阻塞的作用,當匿名函數裡面的業務沒有執行完並講true傳入channel中的時候,這個程式是不會退出的,匿名函數外面會一直在等待。當匿名函數裡面執行到了chann <- true,也就是將true傳入了channel的時候,就不會繼續阻塞,這時候程式就會結束。這就是channel的作用。

使用for range迭代輸出Channel

  • 需要注意的是,當你在對channel 迭代的時候,必須在某個位置明確的關閉這個channel,不然程式就會死結。我們用一個程式碼片段來樣本一下:
1234567891011121314151617181920
package mainimport ("fmt")func main() {chann := make(chan bool)go func() {fmt.Println("Goroutine")chann <- trueclose(chann) //關閉channel}()for v := range chann {fmt.Println(v)}}

Channel 的定義類型

  • Channel 類型的定義格式:
    • ChannelType = ("chan" | "chan" "<-" | "<-" "chan")
  • Channel包含了三種類型的定義,可選的<-代表的是Channel的方向。沒有指定方向的話,Channel就是雙向的,既可以接受資料,也可以發送資料。
    • chan T //可以接收也可以發送
    • chan <- bool //可以發送bool類型的資料
    • <- chan bool //可以接收int類型的資料

無緩衝Channel與緩衝Channel

無緩衝Channel

  • 定義方式 chann := make(chan int)
  • 所謂無緩衝Channel就是在通道中只能傳入1個值,若是傳入的值一直沒有被取走,那麼就會一直阻塞著,直到被取走。可以說是同步阻塞的
  • 需要注意的是,無緩衝Channel一定是先取後傳。當代碼中出現了取的操作時,發現Channel裡面並沒有值,那麼就會發生阻塞,當Channel裡有值了,才會停止阻塞。

緩衝Channel

  • 定義方式 chann := make(chan int,100)
  • 有緩衝Channel,比如緩衝值是100,那麼除非傳入的值已經達到了100了,否則這個Channel中,還是可以不斷地傳值進去。當Channel滿了,就會發生阻塞,等值被取走後,才可以繼續傳值。

如何判斷一組任務是否完成

使用緩衝Channel

12345678910111213141516171819202122232425262728
package mainimport ("fmt""runtime")func main() {runtime.GOMAXPROCS(runtime.NumCPU()) // 設定線程數為當前電腦的CPU數chann := make(chan bool, 10)for i := 0; i < 10; i++ {go Go(chann, i)}for i := 0; i < 10; i++ {<-chann}}func Go(chann chan bool, index int) {a := 1for i := 0; i < 100000000; i++ {a += 1}fmt.Println(index, a)chann <- true}

使用sync包

  • 通過設定一個工作群組,大小為10。每完成一個任務就記錄一次wg.Done(),當10個任務都完成的時候,程式自動結束。
1234567891011121314151617181920212223242526272829
package mainimport ("fmt""runtime""sync")func main() {runtime.GOMAXPROCS(runtime.NumCPU())wg :=sync.WaitGroup{}wg.Add(10)for i := 0; i < 10; i++ {go Go(&wg, i)}wg.Wait()}func Go(wg *sync.WaitGroup, index int) {a := 1for i := 0; i < 100000000; i++ {a += 1}fmt.Println(index, a)wg.Done()}

Select

select 用於多個channel監聽並收發訊息,當任何一個case滿足條件則會執行,若沒有可執行檔case,就會執行default,如果沒有default,程式就會阻塞。

12345678910111213141516171819202122232425262728293031
package mainimport ("fmt""time")func main() {chann := make(chan int)go enqueue(chann)for {select {case v, ok := <-chann:if ok {fmt.Println(v)} else {fmt.Println("close")return}default:fmt.Println("waiting")}}}func enqueue(chann chan int) {time.Sleep(3 * time.Second)chann <- 1close(chann)}

參考

  • http://blog.csdn.net/gaox587/article/details/53005575
  • http://blog.csdn.net/shachao888/article/details/52944212
  • https://github.com/Unknwon/go-fundamental-programming/blob/master/lectures/lecture14.md

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.