package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
// 为所有任务计数
wg.Add(4)
// 执行任务A
go func() {
defer wg.Done()
fmt.Println("Task A is running")
// 模拟任务A执行
}()
// 执行任务B,依赖任务A
go func() {
// 这里等待任务A完成(可通过channel等方式,这里简单示意任务A执行快则不等待)
wg.Wait()
defer wg.Done()
fmt.Println("Task B is running")
// 模拟任务B执行
}()
// 执行任务C,依赖任务A
go func() {
// 这里等待任务A完成(可通过channel等方式,这里简单示意任务A执行快则不等待)
wg.Wait()
defer wg.Done()
fmt.Println("Task C is running")
// 模拟任务C执行
}()
// 执行任务D,依赖任务B和C
go func() {
// 等待任务B和C完成
wg.Wait()
defer wg.Done()
fmt.Println("Task D is running")
// 模拟任务D执行
}()
// 等待所有任务完成
wg.Wait()
fmt.Println("All tasks are completed")
}
通过WaitGroup管理任务间依赖关系
- 初始化计数:在
main
函数开始,通过wg.Add(4)
为4个任务(A、B、C、D)设置初始计数。
- 任务完成通知:每个任务在执行结束前调用
wg.Done()
,表示该任务完成,将WaitGroup的计数减1。
- 等待依赖任务:例如任务B和C需要等待任务A完成,任务D需要等待任务B和C完成,它们通过
wg.Wait()
阻塞,直到依赖任务调用wg.Done()
使计数为0。
避免死锁
- 合理设置计数:确保
wg.Add()
的调用次数和实际任务数量匹配,避免因计数过少导致某些任务未被等待,或计数过多导致wg.Wait()
永远阻塞。
- 及时调用wg.Done():每个任务必须在结束时调用
wg.Done()
,若遗漏会导致wg.Wait()
一直等待,从而产生死锁。
- 避免循环依赖:在设计任务依赖关系时,要避免出现任务间循环依赖的情况,否则会导致死锁。例如,不能出现A依赖B,B依赖C,C又依赖A的情况。