等待协程结束

Go程序随着main()函数的结束而结束,因此,通常的做法是等待所有协程执行完毕。
通常所用的解决方案是利用 sync.WaitGroup 对象。
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup // 1
func routine(i int) {
defer wg.Done() // 3
fmt.Printf("routine %v finished\n", i)
}
func main() {
wg.Add(10) // 2
for i := 0; i < 10; i++ {
go routine(i) // *
}
wg.Wait() // 4
fmt.Println("main finished")
}
-----------Output-------------
routine 3 finished
routine 9 finished
routine 0 finished
routine 4 finished
routine 5 finished
routine 6 finished
routine 7 finished
routine 8 finished
routine 1 finished
routine 2 finished
main finished
WaitGroup 用法中的执行顺序:
  1. 1.
    声明为全局变量。全局变量使得所有函数和方法都可以很简单地访问到它。
  2. 2.
    增加计数器。这必须要在主协程中完成,因为内存模型的原因,并不保证新启动的协程将在4之前执行完。
  3. 3.
    减少计数器。这必须在每个协程退出的位置执行。通过使用延迟(defer)调用,我们可以确保将在函数结束时调用,不论函数是如何被结束的。
  4. 4.
    等待计数器到达0。这也必须在主协程中完成,以避免主程序在所有协程尚未结束之前就退出了。
协程调用的参数在其新启动之前就被求值。
因此,有必要在wg.Add(10)之前就显式地定义其值,以免遇到恐慌(panic)后,计数器无法正常增加。向WaitGroup中添加了10个条目,因此,将在wg.Wait() 把控制权交还main()协程之前等待10个条目。此例中,协程参数i的值是在for循环中定义的。