MST

星途 面试题库

面试题:Go中WaitGroup的基本使用及注意事项

请描述在Go语言中如何正确使用WaitGroup来等待一组goroutine完成任务,同时列举至少两个使用WaitGroup时常见的注意事项,并说明原因。
24.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

使用方式

  1. 初始化WaitGroup:在需要等待一组goroutine完成任务的地方,首先要创建并初始化一个WaitGroup实例。
var wg sync.WaitGroup
  1. 添加任务数:在启动每个goroutine之前,调用wg.Add(1)来告知WaitGroup需要等待的goroutine数量。
wg.Add(1)
go func() {
    defer wg.Done()
    // 具体任务逻辑
}()
  1. 等待所有任务完成:在所有goroutine启动后,调用wg.Wait(),该函数会阻塞当前goroutine,直到所有wg.Done()被调用,即所有goroutine都执行完defer wg.Done()
wg.Wait()

完整示例代码如下:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Goroutine %d is running\n", id)
        }(i)
    }
    wg.Wait()
    fmt.Println("All goroutines have finished")
}

注意事项

  1. 避免重复添加:不要在goroutine内部重复调用wg.Add(1)。如果在goroutine内部再次调用wg.Add(1),可能会导致WaitGroup的计数混乱,使得wg.Wait()永远不会返回。因为wg.Wait()会一直等待计数减为0,重复添加会导致计数无法正确归零。
  2. 确保wg.Done()被调用:每个调用了wg.Add(1)goroutine都必须在任务完成时调用wg.Done()。如果某个goroutine忘记调用wg.Done()wg.Wait()会一直阻塞,因为WaitGroup的计数不会减为0。一般使用defer wg.Done()来确保即使goroutine内部发生错误或提前返回,也能正确减少计数。
  3. 避免提前等待:确保在所有需要等待的goroutine都启动并添加到WaitGroup之后,再调用wg.Wait()。如果在部分goroutine还未启动就调用wg.Wait(),可能会导致这些未启动的goroutine永远不会执行,因为主线程可能已经结束。