当前位置: 技术文章>> 100道Go语言面试题之-Go语言中的sync.WaitGroup是如何实现等待一组goroutine完成的?

文章标题:100道Go语言面试题之-Go语言中的sync.WaitGroup是如何实现等待一组goroutine完成的?
  • 文章分类: 后端
  • 9670 阅读
在Go语言中,`sync.WaitGroup` 是一个非常有用的同步原语,用于等待一组 goroutine 的完成。它内部使用计数器来跟踪活动的 goroutine 数量。每个 goroutine 在开始执行时调用 `Add` 方法来增加计数器的值,并在完成执行时调用 `Done` 方法来减少计数器的值。当计数器的值变为 0 时,所有在 `WaitGroup` 上等待的 goroutine(通过调用 `Wait` 方法)都会被唤醒并继续执行。 ### 实现机制 1. **计数器(Counter)**:`sync.WaitGroup` 内部维护一个计数器,用于跟踪需要等待的 goroutine 数量。 2. **Add 方法**:`Add(delta int)` 方法用于增加或减少计数器的值。当 delta 为正数时,增加计数器的值;当 delta 为负数时,如果减少后的值小于 0,则会引发 panic。这确保了 `WaitGroup` 不会被错误地减少到负数。 3. **Done 方法**:`Done()` 方法是 `Add(-1)` 的便捷封装,用于在 goroutine 完成时减少计数器的值。 4. **Wait 方法**:`Wait()` 方法会阻塞调用它的 goroutine,直到计数器的值变为 0。这意呀着所有通过 `Add` 方法增加的 goroutine 都已经通过调用 `Done` 方法完成了它们的任务。 ### 使用示例 ```go package main import ( "fmt" "sync" "time" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() // 确保 goroutine 结束时减少计数器 fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) // 模拟耗时操作 fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) // 增加计数器 go worker(i, &wg) } wg.Wait() // 等待所有 worker 完成 fmt.Println("All workers have finished") } ``` 在这个例子中,我们启动了 5 个 goroutine 来模拟并行工作。每个 goroutine 在开始时通过 `wg.Add(1)` 增加计数器,并在结束时通过 `defer wg.Done()`(即 `defer wg.Add(-1)`)减少计数器。`main` 函数中的 `wg.Wait()` 调用会阻塞,直到所有 worker goroutine 都通过调用 `Done` 方法完成了它们的任务,此时计数器的值变为 0,`Wait` 方法返回,程序继续执行。
推荐文章