WaitGroup是Go语言中的一个并发原语,用于等待一组goroutine完成执行。它提供了一种方便的方式来同步和管理goroutine的执行。
WaitGroup的结构体定义如下:
type WaitGroup struct {
// 计数器,表示未完成的goroutine数量
counter int
// 互斥锁,用于保护计数器和条件变量的访问
mu Mutex
// 条件变量,用于阻塞等待未完成的goroutine完成
cond Cond
}
WaitGroup的主要方法有:
Add(delta int)
:用于增加计数器的值,表示要等待的goroutine数量增加了。参数delta表示增加的数量,可以为正数或负数。如果delta大于0,表示增加等待的goroutine数量;如果delta小于0,表示减少等待的goroutine数量。当delta为0时,没有实际作用。Done()
:用于减少计数器的值,表示一个goroutine已经完成。当计数器为0时,表示所有goroutine都已完成。Wait()
:用于阻塞当前goroutine,直到计数器为0,也就是所有等待的goroutine都已完成。
使用WaitGroup的基本步骤如下:
- 创建一个WaitGroup对象,例如
var wg sync.WaitGroup
- 在每个需要等待的goroutine中,调用
wg.Add(1)
增加计数器的值,表示加入等待的goroutine。 - 在每个goroutine完成时,调用
wg.Done()
减少计数器的值,表示一个goroutine已经完成。 - 在需要等待所有goroutine完成的地方,调用
wg.Wait()
阻塞当前goroutine,直到计数器为0,也就是所有等待的goroutine都已完成。
下面是一个使用WaitGroup的示例代码:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(3) // 等待3个goroutine完成
go func() {
defer wg.Done() // 完成时减少计数器值
time.Sleep(2 * time.Second)
fmt.Println("goroutine 1 done")
}()
go func() {
defer wg.Done() // 完成时减少计数器值
time.Sleep(1 * time.Second)
fmt.Println("goroutine 2 done")
}()
go func() {
defer wg.Done() // 完成时减少计数器值
time.Sleep(3 * time.Second)
fmt.Println("goroutine 3 done")
}()
wg.Wait() // 等待所有goroutine完成
fmt.Println("all goroutines done")
}
在上面的示例中,我们创建了一个WaitGroup对象wg
,并指定了要等待的goroutine数量为3。然后启动了3个goroutine,每个goroutine都会延迟一段时间后输出一条消息,并调用wg.Done()
表示完成。最后,我们调用wg.Wait()
等待所有goroutine完成,并输出"all goroutines done"。