8.14. Go语言等待组

除了可以使用通道(channel)和互斥锁进行两个并发程序间的同步外,还可以使用等待组进行多个任务的同步。

等待组的方法

方法名

功能

(wg * WaitGroup) Add(delta int)

等待组的计数器 +1

(wg * WaitGroup) Done()

等待组的计数器 -1

(wg * WaitGroup) Wait()

当等待组计数器不等于 0 时阻塞直到变 0。

等待组内部拥有一个计数器,计数器的值可以通过方法调用实现计数器的增加和减少。 当我们添加了N个并发任务进行工作时,就将等待组的计数器值增加N。 每个任务完成时,这个值减1。同时,在另外一个goroutine中等待这个等待组的计数器值为0时,表示所有任务已经完成。

package main

import (
    "fmt"
    "net/http"
    "sync"
)

func main() {
    // 声明一个等待组
    var wg sync.WaitGroup

    // 准备一系列的网站地址
    var urls = []string{
        "http://www.github.com/",
        "https://qiniu.com/",
        "https://www.golangtc.com/",
    }
    // 遍历这些地址
    for _, url := range urls {
        // 每个任务开始时,将等待组增加1
        wg.Add(1)

        //开启一个并发
        go func(url string) {
            // 使用defer,表示函数完成时将等待组值减1
            defer wg.Done()

            //使用http访问提供的地址
            _, err := http.Get(url)
            //访问完成后,打印地址和可能发生的错误
            fmt.Println(url, err)

            // 通过参数传递url地址
        }(url)
    }
    // 等待所有的任务完成
    wg.Wait()
    fmt.Println("over")
}

/*
https://qiniu.com/ <nil>
http://www.github.com/ <nil>
https://www.golangtc.com/ Get https://www.golangtc.com/: net/http: TLS handshake timeout
over
*/

等待一组Goroutine返回

package main

import (
    "sync"
    "fmt"
    "time"
)

func calc(w *sync.WaitGroup, i int)  {
    fmt.Println("calc: ", i)
    time.Sleep(time.Second)
    w.Done()
}

func main()  {
    wg := sync.WaitGroup{}
    for i:=0; i<10; i++ {
        wg.Add(1)
        go calc(&wg, i)
    }
    wg.Wait()
    fmt.Println("all goroutine finish")
}