【golang笔记】go_sync.WaitGroup(29)
Page content
这一篇简单的整理了golang sync.WaitGroup
相关的内容。
1.协程的等待
我们先看看如下代码:
package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 100; i++ {
go fmt.Println(i)
}
time.Sleep(time.Second)
}
主线程为了等待goroutine都运行完毕,
不得不在程序的末尾使用time.Sleep() 来睡眠一段时间
为了解决如上问题,我们可以引进管道
2.Channel的阻塞
package main
import (
"fmt"
)
func main() {
c := make(chan bool, 100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
c <- true
}(i)
}
for i := 0; i < 100; i++ {
<-c
}
}
这么使用,管道是能达到我们的目的的。
但是管道在这里显得有些大材小用,在这里使用管道实际上是不合适的。
而且假设我们有一万、十万甚至更多的for循环,也要申请同样数量大小的管道出来,对内存也是不小的开销。
对于这种情况,go语言中有一个其他的工具sync.WaitGroup
能更加方便的帮助我们达到这个目的。
3.sync.WaitGroup 实现
WaitGroup 对象内部有一个计数器,最初从0开始,
它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。
- Add(n) 把计数器设置为n
- Done() 每次把计数器-1
- wait() 会阻塞代码的运行,直到计数器地值减为0。
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
wg.Wait()
}
这里首先把wg计数设置为100,每个for循环运行完毕都把计数器减一,
主函数中使用Wait() 一直阻塞,直到wg为零——也就是所有的100个for循环都运行完毕。
相对于使用管道来说,WaitGroup 轻巧了许多。
4.sync.WaitGroup的注意事项
4.1 计数器不能为负值
我们不能使用Add() 给wg 设置一个负值,否则代码将会报错
panic: sync: negative WaitGroup counter
4.2 WaitGroup对象不是一个引用类型
WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go f(i, &wg)
}
wg.Wait()
}
// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) {
fmt.Println(i)
wg.Done()
}
4.3 WaitGroup的add操作在协程里做有可能整个协程都会丢失
最好是在协程外记录add
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
countChan := make(chan int, 100)
for i := 0; i < 100; i++ {
go func(countChan chan int) {
wg.Add(1)
countChan <- 1
wg.Done()
}(countChan)
}
wg.Wait()
fmt.Println(len(countChan))
}
改成 =>
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
countChan := make(chan int, 100)
wg.Add(100)
for i := 0; i < 100; i++ {
go func(countChan chan int) {
countChan <- 1
wg.Done()
}(countChan)
}
wg.Wait()
fmt.Println(len(countChan))
}
欢迎大家的意见和交流
email: li_mingxie@163.com