Golang - 教學 tutorial

GoLang - 如何等待多個 goroutine 非同步 (async) 返回結果

在這幾篇,會以 Go 語言的入門基礎進行逐步說明,本篇針對 goroutine 進行說明

前面提到 goroutine, thread 差異 以及 Environment variables,有提到用 goroutines 方式,並且示範 runtime.Gosched() 來讓出CPU切片的流程,

在這裡,我們發現在 goroutine 是透過 async 方式來處理結果,但是主程序在執行 go goroutine 之後,就不會等待返回。

如果在某些情況,我們須等待多個 goroutine 完成,這裡將說明處理方式。

我們先回顧一下前面提到的同時運行多個 goroutine 的範例:

package main

import (
  "fmt"
  "runtime"
)

func showData(txt string) {
  for i := 0; i < 5; i++ {
    runtime.Gosched()
    fmt.Println("RealOutput==>", txt)
  }
}

func main() {
  fmt.Println("stage 1")
  go showData("hi")
  fmt.Println("stage 2")
  showData("all")
  fmt.Println("stage 3")
}

output

stage 1
stage 2
RealOutput==> all
RealOutput==> all
RealOutput==> all
RealOutput==> all
RealOutput==> all
stage 3
RealOutput==> hi
RealOutput==> hi
RealOutput==> hi

這裡會發現一個現象,雖然透過 runtime.Gosched() 將讓出CPU,再接續進行,但是在輸出時,goroutine output 不完全,

等待 Multiple goroutines

主要原因是 go routines 是透過 async 方式,主程序只會關注觸發 goroutine ,而不會等待結果。

如果在一些情況,我們必須等待這些 async 的 goroutiness 完成,可以使用 sync.WaitGroup 的方式來處理,

可以透過 sync WaitGroup 來讓主程序可等待 goroutine 返回結果 在這裡,透過wg.Add()來指定WaitGruop可以容納的 thread wg.Wait() 會等待 WaitGroup 裡面的 thread 執行完畢才會進行 也可以執行 wg.Done() 或者 wg.Add(-1) 的方式直接觸發 wg.Wait()

了解這些方法之後,直接來看範例:

package main

import (
  "fmt"
  "runtime"
  "sync"
)

var wg sync.WaitGroup

func showData(txt string) {
  for i := 0; i < 5; i++ {
    runtime.Gosched()
    fmt.Println("RealOutput==>", txt)
  }
  wg.Done()
}

func main() {
  wg.Add(2)
  fmt.Println("stage 1")
  go showData("hi")
  fmt.Println("stage 2")
  go showData("all")
  wg.Wait()
  fmt.Println("stage 3")

}

output:

stage 1
stage 2
RealOutput==> all
RealOutput==> hi
RealOutput==> all
RealOutput==> hi
RealOutput==> hi
RealOutput==> all
RealOutput==> hi
RealOutput==> hi
RealOutput==> all
RealOutput==> all
stage 3