golang中四種方式實現子goroutine與主協程的同步

golang中四種方式實現子goroutine與主協程的同步

文章出處:趙從亮---原文地址

如何實現子goroutine與主線程的同步

  • 第一種方式:time.sleep(),這種方式很太死板,就不演示了。

  • 第二種方式:使用channel機制,每個goroutine傳一個channel進去然後往裏寫數據,在再主線程中讀取這些channel,直到全部讀到數據了子goroutine也就全部運行完了,那麼主goroutine也就可以結束了。這種模式是子線程去通知主線程結束。

  • package main
    
    import (
        "fmt"
    )
    
    func main() {
        var chanTest = make(chan int)
        var chanMain = make(chan int)
    
        go func() {
            for i := 0; i < 20; i++ {
                chanTest <- i
                fmt.Println("生產者寫入數據", i)
            }
            close(chanTest)
        }()
    
        go func() {
            for v := range chanTest {
                fmt.Println("\t消費者讀出數據", v)
    
            }
    
            chanMain <- 666
        }()
    
        go func() {
            for v := range chanTest {
                fmt.Println("\t\t消費者讀出數據", v)
    
            }
            chanMain <- 666
    
        }()
    
        <-chanMain
        <-chanMain
    
    }

     

  • 第三種方式:使用context中cancel函數,這種模式是主線程去通知子線程結束。

  • package main
    
    import (
        "context"
        "fmt"
        "time"
    )
    
    func gen(ctx context.Context) <-chan int {
        dst := make(chan int)
        n := 1
        go func() {
            for {
                select {
                case <-ctx.Done():
                    fmt.Println("i exited")
                    return // returning not to leak the goroutine
                case dst <- n:
                    n++
                }
            }
        }()
        return dst
    }
    
    func test() {
        
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel() // cancel when we are finished consuming integers
        intChan := gen(ctx)
        for n := range intChan {
            fmt.Println(n)
            if n == 5 {
                break
            }
        }
    }
    func main() {
        test()
        time.Sleep(time.Hour)
    }

     

  • 第四種方式:sync.WaitGroup模式,Add方法設置等待子goroutine的數量,使用Done方法設置等待子goroutine的數量減1,當等待的數量等於0時,Wait函數返回。

  • /使用golang中sync.WaitGroup來實現協程同步  
      
    package main  
      
    import (  
        "fmt"  
        "net/http"  
        "io/ioutil"  
        "time"  
        "os"  
        "sync"  
    )  
      
    var waitGroup = new(sync.WaitGroup)  
    func download(i int ){  
            url := fmt.Sprintf("http://pic2016.ytqmx.com:82/2016/0919/41/%d.jpg", i)  
            fmt.Printf("開始下載:%s\n", url)  
            res,err := http.Get(url)  
            if err != nil || res.StatusCode != 200{  
                fmt.Printf("下載失敗:%s", res.Request.URL)  
            }  
            fmt.Printf("開始讀取文件內容,url=%s\n", url)  
            data ,err2 := ioutil.ReadAll(res.Body)  
            if err2 != nil {  
                fmt.Printf("讀取數據失敗")  
            }  
      
            ioutil.WriteFile(fmt.Sprintf("pic2016/1_%d.jpg", i), data, 0644)  
            //計數器-1  
            waitGroup.Done()  
    }  
      
    func main()  {  
        //創建多個協程,同時下載多個圖片  
        os.MkdirAll("pic2016", 0666)  
        now := time.Now()  
      
        for i :=1; i<24; i++ {  
            //計數器+1  
            waitGroup.Add(1)  
            go download(i)  
        }  
      
        //等待所有協程操作完成  
        waitGroup.Wait()  
        fmt.Printf("下載總時間:%v\n", time.Now().Sub(now))  
    } 

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章