Golang並發(四)- buffered channel 和 Worker Pools

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

What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back.

你所浪費的今天是昨天死去的人奢望的明天; 你所厭惡的現在是未來的你回不去的曾經。

 

Buffered channel

    之前我們說的channel都是不帶緩衝的,無論發送和接收都會導致阻塞。

    緩衝Channel的特點是:只有當發送至緩衝區存滿後導致阻塞, 接受也是如此。

    建立方式: ch:= make(chan Type , capacity)

    capacity 容量, 當capacity = 0 時, 為無緩衝channel,通常省略而已。

package mainimport ("fmt")func main() {ch := make(chan string, 2)ch <- "naveen"ch <- "paul"fmt.Println(<- ch)fmt.Println(<- ch)  // 注釋此行,會不會deadlock???}

 

下這個例子請認真思考,有助於理解buffered channel:

package mainimport (      "fmt"    "time")func write(ch chan int) {      for i := 0; i < 5; i++ {        ch <- i        fmt.Println("successfully wrote", i, "to ch")    }    close(ch)}func main() {      ch := make(chan int, 2)    go write(ch)    time.Sleep(2 * time.Second)    for v := range ch {        fmt.Println("read value", v,"from ch")        time.Sleep(2 * time.Second)    }}

解釋:

    當main程建立一個有容量為2的channel,然後在goroutine中迴圈寫入, 在寫入兩次後, goroutine阻塞, main程同時也進入了sleep中,當range開始接收後,goroutine發現又可以繼續寫入。

輸出:

successfully wrote 0 to chsuccessfully wrote 1 to chread value 0 from chsuccessfully wrote 2 to chread value 1 from chsuccessfully wrote 3 to chread value 2 from chsuccessfully wrote 4 to chread value 3 from chread value 4 from ch

一開始寫入兩次,是因為channel容量為2, 不需要讀取就可寫入。 

最後連續兩次讀,是因為當range讀取一次後, goroutine立刻寫入一次,所以channel中始終保持2個資料。

 

概念: 長度與容量

    容量是指channel最大的儲存長度。 長度是指當前channel中正在排隊的資料長度。

  代碼說明:

package mainimport (      "fmt")func main() {      ch := make(chan string, 3)    ch <- "資料1"ch <- "資料2"    //容量為3, 但是其中資料只有2個    fmt.Println("capacity is", cap(ch))     //資料長度為2    fmt.Println("length is", len(ch))     //讀取一次    fmt.Println("read value", <-ch)   //資料長度為1, 但是容量還是3    fmt.Println("new length is", len(ch)) }

輸出:

capacity is 3length is 2read value 資料1new length is 1

 

WaitGroup

工作池的實現離不開WaitGroup, 下面講一下關於WariGroup。

如果一個main程中有三個goroutine, 要想獲得這三個goroutine的輸出,那麼 需要使用WaitGroup阻塞main程,等待所有goroutine結束。

package mainimport ("fmt""sync""time")func ProcessEcho( i int , w *sync.WaitGroup){fmt.Println("協程", i , "開始")time.Sleep(1*time.Second)fmt.Println("協程", i , "結束")w.Done()}func main(){var w sync.WaitGroupMax := 10for i:= 0; i<Max ;i++  {w.Add(1)go ProcessEcho(i, &w)}w.Wait()fmt.Println("main執行完成並退出。")}

解釋:

    main程啟動10個協程, 每天啟動都高速WaitGroup來添加一個監聽,每個goroutine結束都標記一次結束。 main程中等待所有標記完成,結束阻塞。

注意點:

1. 為什麼go ProcessEcho中使用的是w的指標?!

2. goroutine的輸出是沒有規律的。

 

 

細看工作池的實現吧:

package mainimport ("fmt""sync""time")//任務結構type Job struct {id       intrandomno int}//接受資料結構type Result struct {job         Jobsumofdigits int}var jobs = make(chan Job, 10)var results = make(chan Result, 10)func digits(number int) int {time.Sleep(2 * time.Second)return number}func worker(i int , wg *sync.WaitGroup) {for job := range jobs {output := Result{job, digits(i)}results <- output}wg.Done()}func createWorkerPool(noOfWorkers int) {var wg sync.WaitGroupfor i := 0; i < noOfWorkers; i++ {wg.Add(1)go worker(i,&wg)}wg.Wait()close(results)}func allocate(noOfJobs int) {for i := 0; i < noOfJobs; i++ {randomno := ijob := Job{i, randomno}jobs <- job}close(jobs)}func result(done chan bool) {for result := range results {fmt.Printf("Job id %d, input random no %d , sum of digits %d\n", result.job.id, result.job.randomno, result.sumofdigits)}done <- true}func main() {startTime := time.Now()noOfJobs := 12 // 任務數go allocate(noOfJobs)done := make(chan bool)go result(done)noOfWorkers := 3 // 執行者createWorkerPool(noOfWorkers)<-doneendTime := time.Now()diff := endTime.Sub(startTime)fmt.Println("total time taken ", diff.Seconds(), "seconds")}

 

 

 

 

 

相關文章

聯繫我們

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