golang 协程并发代码 demo

本文介绍了如何在Go语言中使用sync.WaitGroup来控制外层和内层循环中的多协程并发。通过示例代码展示了如何在每个元素上启动新协程,并在内部创建子协程,确保所有任务执行完毕后主协程才退出。同时,讨论了WaitGroup的Add、Done和Wait方法的正确使用方式,以及如何通过channel限制协程数量。
摘要由CSDN通过智能技术生成

有时我们可能想既在外层循环中实现多协程并发,还想在内层循环中实现多协程并发,那么我们需要同时在内层和外层使用 WaitGroup() 来控制主协程不退出。

下面是一个 demo:

博客平台纯手敲,可能存在字符拼写错误

import (
	"fmt"
	"sync"  
)

func handleTask() {
  demoList := []string{"123", "456", "abc", "ddd"}

  var wg = sync.WaitGroup{}
  
  for idx, item := range demoList {
    // 每个元素创建一个新协程去处理
    wg.Add(1) // 
    go func(idx int){
      defer wg.Done() // 协程退出前将 wg 计数器减一,否则最后计数器无法减为0,会一直卡在 wg.wait() 那一行
      
      // 内部还想新建子协程去做不同的事,减少执行时间
      var innerWg = sync.WaitGroup{} // 
      
      innerWg.Add(1)
      go func(){
        defer innerWg.Done() // 子协程退出前将 innerWg 的计数器减一
        fmt.Printf("子协程一正在执行")
      }
      
      innerWg.Add(1)
      go func(){
        defer innerWg.Done() // 子协程退出前将 innerWg 的计数器减一
        fmt.Printf("子协程二正在执行")
      }
      innerWg.Wait() // 等所有所有子协程执行完才继续往下执行

      fmt.Printf("外层协程%d即将执行完毕", idx)

    }(idx)
  }
  
  wg.Wait() // 等待 wg 的计数器减为0后才继续往下执行,等待所有的协程处理完毕
  
  fmt.Println("Execution completed. will exit")
}

func main() {

  handleTask()
}
  • sync.WaitGroup{}:一个内部加锁的计数器,Add(num) 函数会使计数器加上对应的 num 值;Done() 函数会使计数器减一;Wait() 函数会一直阻塞程序的继续向下运行,直到计数器减为0。
  • Add() 函数需要在子协程开辟前执行;Done() 函数最好在子协程最开始的 defer 中执行,保证子协程退出后一定会将计数器减一,否则主协程可能因为计数器不为 0 一直卡主;Wait() 函数一般放在主协程里,且是子协程执行完毕后。
  • 如果需要控制协程的数量,还得引入 channel ,参考:5、Go是否可以无限go? 如何限定数量?,文末是从此文拷贝过来的一段代码

下面是内层子协程并发的另一种写法

博客平台纯手敲,可能存在字符拼写错误

import (
	"fmt"
	"sync"  
)

func handleTask() {
  demoList := []string{"123", "456", "abc", "ddd"}

  var wg = sync.WaitGroup{}
  
  for idx, item := range demoList {
    // 每个元素创建一个新协程去处理
    wg.Add(1) // 
    go func(idx int){
      defer wg.Done() // 协程退出前将 wg 计数器减一,否则最后计数器无法减为0,会一直卡在 wg.wait() 那一行
      
      // 内部还想新建子协程去做不同的事,减少执行时间
      var innerWg = sync.WaitGroup{} // 
      for i := 1; i < 3; i++ {
        innerWg.Add(1)
        go func(){
          defer innerWg.Done() // 子协程退出前将 innerWg 的计数器减一
          fmt.Printf("子协程 %d 正在执行\n", i)
        }
      }

      fmt.Printf("外层协程%d即将执行完毕", idx)

    }(idx)
  }
  
  wg.Wait() // 等待 wg 的计数器减为0后才继续往下执行,等待所有的协程处理完毕
  
  fmt.Println("Execution completed. will exit")
}

func main() {

  handleTask()
}

channel 与 sync 同步组合方式控制协程数量

代码来自:5、Go是否可以无限go? 如何限定数量?

package main

import (
    "fmt"
    "math"
    "sync"
    "runtime"
)

var wg = sync.WaitGroup{}

func busi(ch chan bool, i int) {

    fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())

    <-ch

    wg.Done()
}

func main() {
    //模拟用户需求go业务的数量
    task_cnt := math.MaxInt64

    ch := make(chan bool, 3)

    for i := 0; i < task_cnt; i++ {
		wg.Add(1)

        ch <- true

        go busi(ch, i)
    }

	  wg.Wait()
}

参考5、Go是否可以无限go? 如何限定数量?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值