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)) }