本章介绍go语言sync包中的两个同步原语:
- WaitGroup - 主要用于等待一组并发的任务
- Once - 用于在并发环境中仅执行一次的任务
1. WaitGroup
WaitGroup用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。
基本用法说明:
// WaitGroup内部维护了一个计数器,用于统计需要等待的任务数量,当计数器的值等于0的时候,Wait函数就会直接返回,否则阻塞。
var wg sync.WaitGroup
// 内部计数加2
wg.Add(2)
// 内部计数减1
wg.Done()
// 如果内部计数器大于0,则阻塞,计数器等于0则返回。
wg.Wait()
例子:
// 初始化WaitGroup对象
var wg sync.WaitGroup
// url数组
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
// 访问所有的url
for _, url := range urls {
// WaitGroup的计数加1
wg.Add(1)
// 使用协程访问URL
go func(url string) {
// 调用WaitGroup的Done函数,实际上就是内部计数减1
defer wg.Done()
// 访问url
http.Get(url)
}(url)
}
// 调用WaitGroup的Wati函数等待所有url加载完成。
// 因为有3个url需要访问,Add函数调用3次,计数器等于3,
// url访问完成后,调用Done函数3次,计数器就会等于0
wg.Wait()
2. Once
Once是只执行一次动作的对象。
例子:
// 定义Once对象
var once sync.Once
onceBody := func() {
fmt.Println("我只跑一次。")
}
done := make(chan bool)
for i := 0; i < 10; i++ {
// 并发执行10次
go func() {
// 调用Once对象的Do函数执行onceBody函数
// 注意:一个Once对象只能执行一次,无论调用多少次Do函数。
once.Do(onceBody)
done <- true
}()
}
for i := 0; i < 10; i++ {
<-done
}
输出:
我只跑一次。