面试题答案
一键面试WaitGroup确保并发环境下数据安全及操作同步的原理
- 计数机制:WaitGroup内部维护一个计数器。通过
Add
方法增加计数器的值,通常在启动新的并发任务前调用,用于告知WaitGroup有多少个任务需要等待完成。当并发任务完成时,使用Done
方法,它实际上是对计数器减1。 - 阻塞等待:主线程或其他需要等待所有并发任务完成的地方调用
Wait
方法,该方法会阻塞当前 goroutine,直到计数器的值变为0。这就确保了在所有任务完成之前,相关的后续操作不会提前执行,从而实现了操作同步。 - 数据安全:由于WaitGroup本身并不直接处理数据,而是用于协调 goroutine 的执行顺序,它间接保证了数据安全。通过确保所有涉及数据处理的 goroutine 完成后再进行其他操作,避免了数据竞争等问题。例如在多个 goroutine 对共享数据进行写入操作时,只有当所有写入操作完成后,读取该数据的操作才能进行,防止读到未完成修改的数据。
示例代码
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
// 设置计数器为3,表示有3个任务
wg.Add(3)
// 启动第一个goroutine
go func() {
defer wg.Done()
fmt.Println("Goroutine 1 is running")
}()
// 启动第二个goroutine
go func() {
defer wg.Done()
fmt.Println("Goroutine 2 is running")
}()
// 启动第三个goroutine
go func() {
defer wg.Done()
fmt.Println("Goroutine 3 is running")
}()
// 等待所有goroutine完成
wg.Wait()
fmt.Println("All goroutines have finished")
}
在上述代码中,通过wg.Add(3)
设置了等待组的计数器为3,代表有3个并发任务。每个 goroutine 在完成时调用wg.Done()
使计数器减1。wg.Wait()
会阻塞主线程,直到计数器变为0,即所有3个 goroutine 都执行完wg.Done()
,此时才会打印出All goroutines have finished
。