基础简介
sync.WaitGroup也是一个经常会用到的同步方法,它的使用场景是在一个goroutine等待一组goroutine执行完成。
sync.WaitGroup拥有一个内部计数器。当计数器等于0时,则Wait()方法会立即返回。
否则它将阻塞执行Wait()方法的goroutine直到计数器等于0时为止。
要增加计数器,我们必须使用Add(int)方法。要减少它,我们可以使用Done()(将计数器减1),
也可以传递负数给Add方法把计数器减少指定大小,Done()方法底层就是通过Add(-1)实现的。
示例1:
多个数据发送者与一个接收者
package main
import (
"fmt"
"sync"
// "time"
)
func main() {
wg := &sync.WaitGroup{}
ch := make(chan int,5)
done := make(chan struct{})
send := func(id int) {
defer wg.Done()
for i := 0; ; i++ {
select {
case <- done:
fmt.Printf("sender #%d exit\n",id)
return
case ch <- (id+1) * 100 + i:
fmt.Println("id:", id, "ch:", ch)
}
}
}
recv := func() {
count := 0
for i := range ch {
fmt.Printf("receiver get %d \n ",i)
count ++
if count >= 10 {
close(done)
return
}
}
}
wg.Add(3)
go send(0)
go send(1)
go send(2)
//time.Sleep(200 * time.Millisecond)
recv()
wg.Wait()
}
运行效果如下:
robot@ubuntu:~/gomod/src/sync$ go run syncWaitGroup.go
id: 2 ch: 0xc0000be000
id: 2 ch: 0xc0000be000
id: 2 ch: 0xc0000be000
id: 2 ch: 0xc0000be000
id: 2 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
receiver get 300
receiver get 100
receiver get 301
receiver get 302
receiver get 303
receiver get 304
receiver get 200
receiver get 305
receiver get 101
id: 0 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
id: 0 ch: 0xc0000be000
receiver get 102
sender #0 exit
id: 2 ch: 0xc0000be000
sender #2 exit
id: 1 ch: 0xc0000be000
sender #1 exit
示例2:
多个数据发送者与多个接收者
robot@ubuntu:~/gomod/src/sync$ cat syncWaitGroup1.go
package main
import (
"fmt"
"sync"
"time"
)
func main() {
wg := &sync.WaitGroup{}
ch := make(chan int,5)
done := make(chan struct{})
send := func(id int) {
defer wg.Done()
for i := 0; ; i++ {
select {
case <- done:
fmt.Printf("sender # %d exit\n",id)
return
case ch <- (id+1) * 100 + i:
fmt.Println("send id:", id, "flag:", (id+1)*100+i)
}
}
}
recv := func(id int) {
defer wg.Done()
for {
select {
case <- done:
fmt.Printf("receiver # %d exit \n",id)
return
case i := <-ch:
fmt.Printf("recevier # %d get %d \n",id, i)
time.Sleep(time.Millisecond)
}
}
}
wg.Add(6)
go send(0)
go send(1)
go send(2)
go recv(0)
go recv(1)
go recv(2)
time.Sleep(time.Millisecond)
close(done)
wg.Wait()
}
运行效果如下:
robot@ubuntu:~/gomod/src/sync$ go run syncWaitGroup1.go
send id: 0 flag: 100
send id: 0 flag: 101
send id: 0 flag: 102
send id: 0 flag: 103
send id: 0 flag: 104
recevier # 2 get 100
recevier # 0 get 101
send id: 0 flag: 105
recevier # 1 get 102
send id: 0 flag: 106
send id: 2 flag: 300
recevier # 1 get 300
send id: 0 flag: 107
send id: 0 flag: 108
sender # 0 exit
recevier # 0 get 104
sender # 2 exit
recevier # 2 get 103
sender # 1 exit
recevier # 2 get 105
recevier # 1 get 106
recevier # 0 get 107
recevier # 0 get 108
receiver # 2 exit
receiver # 1 exit
receiver # 0 exit