Golang讓協程交替輸出

來源:互聯網
上載者: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.

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

     之前用Golang寫過一篇關於下載的文章(https://my.oschina.net/90design/blog/1607131), 最後提到:如果新需求是同時下載,並且按循序下載,最近看到在論壇裡有人又再問起,就想起來更新一下此問題。

開始

  1. 兩個協程交替輸出1-20 

package mainimport "fmt"func main() {A := make(chan bool, 1)B := make(chan bool)Exit := make(chan bool)go func() {for i := 1; i <= 20; i++ {if ok := <-A; ok {fmt.Println("A = ", 2*i-1)B <- true}}}()go func() {defer func() {close(Exit)}()for i := 1; i <= 20; i++ {if ok := <-B; ok {fmt.Println("B : ", 2*i)A <- true}}}()A <- true<-Exit}

解釋:

首先給通道A一個緩衝,並在主進程中發送資料,使其堵塞,在第一個Goroutine中通道A接收並開始執行, 此時B是堵塞等待的, 等A執行完成發送資料到通道B, B開始執行。

 

擴充寫法

不過在論壇看到其他人碼友直接使用一個輸出通道搞定,貼出來大家看看:

func main() {    ch := make(chan int)    exit := make(chan struct{})    go func() {        for i := 1; i <= 20; i++ {            println("g1:", <-ch)  // 執行步驟1, 執行步驟5            i++  //執行步驟6            ch <- i // 執行步驟7        }    }()    go func() {        defer func() {            close(ch)            close(exit)        }()        for i := 0; i < 20; i++ {            i++  // 執行步驟2            ch <- i  //執行步驟3            println("g2:", <-ch) //執行步驟4        }    }()    <-exit}

 

問題延伸

問題延伸出來, 如果 >2 個協程呢?

    多個協程,按一定順序執行任務

package mainimport ("fmt""io")var (num intA    = make(chan int)B    = make(chan int)C    = make(chan int)D    = make(chan int)exit = make(chan bool))func main() {// 開啟多協程go Aa()go Bb()go Cc()go Dd()// 接收要輸出的最大數fmt.Println("輸入要輸出的最大數值:")_, ok := fmt.Scanf("%d\n", &num)if ok == io.EOF{return}// 觸發協程同步執行A <- 1// 執行結束if <-exit{return}}func Aa() {for {if count := <-A;  count <= num {fmt.Println("A -> ", count)count++B <- count}else{fmt.Println("在通道D執行完成")close(exit)return}}}func Bb() {for {if count := <-B;  count <= num {fmt.Println("B -> ", count)count++C <- count}else{fmt.Println("在通道A執行完成")close(exit)return}}}func Cc() {for {if count := <-C; count <= num {fmt.Println("C -> ", count)count++D <- count}else{fmt.Println("在通道B執行完成")close(exit)return}}}func Dd() {for {if count, ok := <-D; ok && count <= num {fmt.Println("D -> ", count)count++A <- count}else{fmt.Println("在通道C執行完成")close(exit)return}}}

 

 解釋:

    以上代碼通過多個協程建立多個方法的方式完成多協程的執行任務, 你可能會問了: 如果100個協程還要有100個對應的方法? 答案是: 肯定 , 不可能啊, 立馬來個最佳化方案。

最佳化方案:

package mainimport ("fmt""io""strconv")var (num   int // 要輸出的最大值line  = 0 // 通道發送計數器exit  = make(chan bool)chans []chan int // 要初始化的協程數量)func main() {// 開啟4個協程chans = []chan int{make(chan int),make(chan int),make(chan int),make(chan int) }// 多協程啟動入口go ChanWork(chans[0])// 接收要輸出的最大數fmt.Println("輸入要輸出的最大數值:")_, ok := fmt.Scanf("%d\n", &num)if ok == io.EOF {return}// 觸發協程同步執行chans[0] <- 1// 執行結束if <-exit {return}}func ChanWork(c chan int) {// 協程數lens := len(chans)for {// count為輸出計數器if count := <-chans[line]; count <= num {fmt.Println("channel "+strconv.Itoa(line)+" -> ", count)count++// 下一個發送通道line++if line >= lens {line = 0 //迴圈,防止索引越界}go ChanWork(chans[line])chans[line] <- count} else {            // 通道編號問題處理id := 0if line == 0{id = lens-1}else{id = line-1}fmt.Println("在通道" + strconv.Itoa(id) + "執行完成")close(exit)return}}}

執行的結果:

解釋:

   可以說是通過遞迴的方式,通過一個協程執行完成再來產生第二個協程的方式, 本人是通過輪訓channels的slice來完成協程之間的同步任務, 如果還有更好的方式請留言哦。 就算你有100W個也不懼怕, 看你配置了。

 

結語

就寫到這裡吧,詳細的最佳化後期再完成, 細嚼才能慢咽啊!

建議很重要,交流進步才是硬道理啊!

 

 

 

 

聯繫我們

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