Go语言sync.WaitGroup应用详解

基础简介

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 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值