面试题答案
一键面试使用方式
- 初始化
WaitGroup
:在需要等待一组goroutine
完成任务的地方,首先要创建并初始化一个WaitGroup
实例。
var wg sync.WaitGroup
- 添加任务数:在启动每个
goroutine
之前,调用wg.Add(1)
来告知WaitGroup
需要等待的goroutine
数量。
wg.Add(1)
go func() {
defer wg.Done()
// 具体任务逻辑
}()
- 等待所有任务完成:在所有
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")
}
注意事项
- 避免重复添加:不要在
goroutine
内部重复调用wg.Add(1)
。如果在goroutine
内部再次调用wg.Add(1)
,可能会导致WaitGroup
的计数混乱,使得wg.Wait()
永远不会返回。因为wg.Wait()
会一直等待计数减为0,重复添加会导致计数无法正确归零。 - 确保
wg.Done()
被调用:每个调用了wg.Add(1)
的goroutine
都必须在任务完成时调用wg.Done()
。如果某个goroutine
忘记调用wg.Done()
,wg.Wait()
会一直阻塞,因为WaitGroup
的计数不会减为0。一般使用defer wg.Done()
来确保即使goroutine
内部发生错误或提前返回,也能正确减少计数。 - 避免提前等待:确保在所有需要等待的
goroutine
都启动并添加到WaitGroup
之后,再调用wg.Wait()
。如果在部分goroutine
还未启动就调用wg.Wait()
,可能会导致这些未启动的goroutine
永远不会执行,因为主线程可能已经结束。