面试题答案
一键面试package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
// 为任务A、B、C添加计数
wg.Add(3)
// 任务A
go func() {
defer wg.Done()
fmt.Println("任务A开始执行")
// 模拟任务A的工作
fmt.Println("任务A执行完毕")
}()
// 任务B
go func() {
defer wg.Done()
fmt.Println("任务B开始执行")
// 模拟任务B的工作
fmt.Println("任务B执行完毕")
}()
// 任务C
go func() {
// 等待任务A和B完成
wg.Wait()
defer wg.Done()
fmt.Println("任务C开始执行")
// 模拟任务C的工作
fmt.Println("任务C执行完毕")
}()
// 等待所有任务完成
wg.Wait()
fmt.Println("所有任务执行完毕")
}
代码说明
-
WaitGroup的使用:
wg.Add(3)
:初始化WaitGroup的计数器为3,代表有三个任务(A、B、C)。- 每个任务函数中都有
defer wg.Done()
,表示任务完成时将计数器减1。 - 在任务C中,
wg.Wait()
会阻塞任务C的执行,直到WaitGroup的计数器归零,即任务A和B都完成。 - 最后在
main
函数末尾再次调用wg.Wait()
,确保所有任务都执行完毕后程序才退出。
-
避免常见并发错误:
- 死锁:通过正确设置
wg.Add
、wg.Done
和wg.Wait
的位置避免死锁。例如,如果在任务C中没有wg.Wait()
,任务C可能在任务A和B未完成时就开始执行,导致不符合依赖关系。如果没有在每个任务中调用wg.Done()
,wg.Wait()
可能永远阻塞,造成死锁。 - 数据竞争:在这段代码中,每个任务相对独立,不存在对共享资源的读写操作,所以没有数据竞争问题。如果存在共享资源,需要使用互斥锁(如
sync.Mutex
)来保护共享资源,避免数据竞争。
- 死锁:通过正确设置