在线文档  >   Golang练习   >   WaitGroup

在Go中,要等待多个 协程 完成,我们可以使用一个wait group(等待组)。

package main

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

// 这是我们将在每个协程中运行的函数。
func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)

    // 休眠以模拟一项耗时的任务。
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {

    // 这个 WaitGroup 用于等待此处启动的所有goroutine完成。
    // 注意:如果WaitGroup显式传递到函数中,它应该是 `指针`。
    var wg sync.WaitGroup

    // 启动几个协程,并为每个WaitGroup添加计数器。
    for i := 1; i <= 5; i++ {
        wg.Add(1)
        // Avoid re-use of the same `i` value in each goroutine closure.
        // See [the FAQ](https://golang.org/doc/faq#closures_and_goroutines)
        // for more details.
        // 避免在每个 协程 闭包中重用相同的`i`值。
        // 更多细节请参见 [常见问题解答]。
        i := i

        // 将worker调用包装在一个闭包中,确保告诉WaitGroup这个worker已经完成。
        // 这样,worker本身不必意识到涉及其执行的并发原语。
        go func() {
            defer wg.Done()
            worker(i)
        }()
    }

    // 一直阻塞,直到WaitGroup计数器回到0;所有worker都通知他们已经完成。
    wg.Wait()
}

请注意,wg.Wait()这种方法没有一种直接的方式从worker那里传递错误。对于更高级的用例,请考虑使用errgroup包
常见问题解答

运行结果如下:

$ go run waitgroups.go
Worker 5 starting
Worker 3 starting
Worker 4 starting
Worker 1 starting
Worker 2 starting
Worker 4 done
Worker 1 done
Worker 2 done
Worker 5 done
Worker 3 done

对于每个调用,启动和完成的工作线程的顺序可能不同。