golang学习笔记--WaitGroup

sync.WaitGroup 作用

  1. 等待一组协程完成
  2. 工作原理:通过计数器来获取协程的完成情况
  3. 启动一个协程时计数器+1,协程退出时计数器-1
  4. 通过wait方法阻塞主协程,等待计数器清零后才能继续执行后续操作

sync.WaitGroup 应用场景

  1. 通过协程并行执行一组任务,且任务全部完成后才能进行下一步操作的情况
  2. 例如: 汽车的生成,所有零件可以并行生产,只能等所有零件生成完成后,才能组装

sync.WaitGroup 陷阱

  1. 协程间传递时需要以指针的方式或闭包的方式引用 WaitGroup 对象。否则将会造成死锁

sync.Cond 作用

  1. 设置一组协程根据条件阻塞,可以根据不同的条件阻塞
  2. 可以根据条件唤醒相对应的协程

sync.Cond 应用场景

  1. 应用于一发多收的场景,即一组协程需要等待某一个协程完成一些前置准备的情况

sync.Cond 注意事项

  1. 被叫方必须持有锁
  2. 主叫方可以持有锁,但允许不持有
  3. 尽可能的减少无效唤醒

WaitGroup代码示例

代码1

循环50亿次和协程时间对比:

package waitgroup

import (
	"fmt"
	"sync"
	"time"
)

func WaitGroupCase() {
	var a, b = 1000, 10000
	start := time.Now()
	for i := 0; i < 5000000000; i++ {
		multi(a, b)
	}
	t := time.Since(start)
	fmt.Println(t)

	fmt.Println("------------------")

	start2 := time.Now()
	wg := sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 500000000; j++ {
				multi(a, b)

			}
		}()
	}
	wg.Wait()
	t2 := time.Since(start2)
	fmt.Println(t2)
}

func multi(a, b int) int {
	return a * b
}

执行结果

代码2

package waitgroup

import (
	"fmt"
	"sync"
	"time"
)

func WaitGroupCase1() {
	ch := make(chan []int, 1000)
	start := time.Now()

	wg2 := sync.WaitGroup{}
	wg2.Add(1)
	go func() {
		defer wg2.Done()
		i := 0
		for itme := range ch {
			fmt.Println(multi(itme[0], itme[1]))
			i++
		}
		time.Sleep(3 * time.Second)
		fmt.Println("数据处理完成,数据条数:", i)
	}()

	wg := &sync.WaitGroup{}
	for i := 0; i < 2; i++ {
		wg.Add(1)
		wg2.Add(1)
		go func(wg1 *sync.WaitGroup) {
			defer wg1.Done()
			defer wg2.Done()
			for j := 0; j < 500; j++ {
				ch <- []int{i, j}
			}
		}(wg)
	}
	wg.Wait()
	close(ch)
	wg2.Wait()

	t := time.Since(start)
	fmt.Println("处理时长为:", t)
}

func multi(a, b int) int {
	return a * b
}

代码3:

求出800以内的素数并打印出来

package main

import (
	"fmt"
	"sync"
)

func putNum(intChan chan int, wg *sync.WaitGroup) {
	defer wg.Done() // 协程结束时,计数-1
	for i := 1; i <= 800; i++ {
		intChan <- i
	}
	close(intChan)
}

func primeNum(intChan chan int, primeChan chan int, wg *sync.WaitGroup) {
	defer wg.Done() // 协程结束时,计数-1
	for {
		num, ok := <-intChan
		if !ok {
			break
		}

		if num == 1 {
			continue
		}

		flag := true
		for i := 2; i <= num/2; i++ {
			if num%i == 0 {
				flag = false
				break
			}
		}
		if flag {
			fmt.Println("primeNum写入了", num)
			primeChan <- num
		}
	}
	fmt.Println("有一个primeNum协程因为取不到数据,退出了")
}

func main() {
	intChan := make(chan int, 100)
	primeChan := make(chan int, 10)
	wg := sync.WaitGroup{}

	wg.Add(1) // 启动一个协程 计数+1
	go putNum(intChan, &wg)

	// 开启4个协程,从intChan取出数据,并判断是否是素数,
	// 如果是素数,就放到primeChan中
	for i := 0; i < 4; i++ {
		wg.Add(1) // 启动一个协程 计数+1
		go primeNum(intChan, primeChan, &wg)
	}

	go func() {
		//等待所有协程结束后关闭primeChan
		wg.Wait()
		close(primeChan)
	}()

	for v := range primeChan {
		fmt.Println(v)
	}
	fmt.Println("main()进程结束")
}

执行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值