• golang 协程并发代码 demo


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

    下面是一个 demo:

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

    1. import (
    2. "fmt"
    3. "sync"
    4. )
    5. func handleTask() {
    6. demoList := []string{"123", "456", "abc", "ddd"}
    7. var wg = sync.WaitGroup{}
    8. for idx, item := range demoList {
    9. // 每个元素创建一个新协程去处理
    10. wg.Add(1) //
    11. go func(idx int){
    12. defer wg.Done() // 协程退出前将 wg 计数器减一,否则最后计数器无法减为0,会一直卡在 wg.wait() 那一行
    13. // 内部还想新建子协程去做不同的事,减少执行时间
    14. var innerWg = sync.WaitGroup{} //
    15. innerWg.Add(1)
    16. go func(){
    17. defer innerWg.Done() // 子协程退出前将 innerWg 的计数器减一
    18. fmt.Printf("子协程一正在执行")
    19. }
    20. innerWg.Add(1)
    21. go func(){
    22. defer innerWg.Done() // 子协程退出前将 innerWg 的计数器减一
    23. fmt.Printf("子协程二正在执行")
    24. }
    25. innerWg.Wait() // 等所有所有子协程执行完才继续往下执行
    26. fmt.Printf("外层协程%d即将执行完毕", idx)
    27. }(idx)
    28. }
    29. wg.Wait() // 等待 wg 的计数器减为0后才继续往下执行,等待所有的协程处理完毕
    30. fmt.Println("Execution completed. will exit")
    31. }
    32. func main() {
    33. handleTask()
    34. }
    • sync.WaitGroup{}:一个内部加锁的计数器,Add(num) 函数会使计数器加上对应的 num 值;Done() 函数会使计数器减一;Wait() 函数会一直阻塞程序的继续向下运行,直到计数器减为0。
    • Add() 函数需要在子协程开辟前执行;Done() 函数最好在子协程最开始的 defer 中执行,保证子协程退出后一定会将计数器减一,否则主协程可能因为计数器不为 0 一直卡主;Wait() 函数一般放在主协程里,且是子协程执行完毕后。
    • 如果需要控制协程的数量,还得引入 channel ,参考:5、Go是否可以无限go? 如何限定数量?,文末是从此文拷贝过来的一段代码

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

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

    1. import (
    2. "fmt"
    3. "sync"
    4. )
    5. func handleTask() {
    6. demoList := []string{"123", "456", "abc", "ddd"}
    7. var wg = sync.WaitGroup{}
    8. for idx, item := range demoList {
    9. // 每个元素创建一个新协程去处理
    10. wg.Add(1) //
    11. go func(idx int){
    12. defer wg.Done() // 协程退出前将 wg 计数器减一,否则最后计数器无法减为0,会一直卡在 wg.wait() 那一行
    13. // 内部还想新建子协程去做不同的事,减少执行时间
    14. var innerWg = sync.WaitGroup{} //
    15. for i := 1; i < 3; i++ {
    16. innerWg.Add(1)
    17. go func(){
    18. defer innerWg.Done() // 子协程退出前将 innerWg 的计数器减一
    19. fmt.Printf("子协程 %d 正在执行\n", i)
    20. }
    21. }
    22. fmt.Printf("外层协程%d即将执行完毕", idx)
    23. }(idx)
    24. }
    25. wg.Wait() // 等待 wg 的计数器减为0后才继续往下执行,等待所有的协程处理完毕
    26. fmt.Println("Execution completed. will exit")
    27. }
    28. func main() {
    29. handleTask()
    30. }

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

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

    1. package main
    2. import (
    3. "fmt"
    4. "math"
    5. "sync"
    6. "runtime"
    7. )
    8. var wg = sync.WaitGroup{}
    9. func busi(ch chan bool, i int) {
    10. fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())
    11. <-ch
    12. wg.Done()
    13. }
    14. func main() {
    15. //模拟用户需求go业务的数量
    16. task_cnt := math.MaxInt64
    17. ch := make(chan bool, 3)
    18. for i := 0; i < task_cnt; i++ {
    19. wg.Add(1)
    20. ch <- true
    21. go busi(ch, i)
    22. }
    23. wg.Wait()
    24. }

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

  • 相关阅读:
    【vue设计与实现】非原始值的响应式方案 10-如何代理Set和Map
    强化学习:伪代码汇总及用DQN求解MountainCar-v0问题代码
    【Android11】在内置的Tvsettings的界面中显示以太网Mac地址
    MES生产管理系统,你真的需要吗?
    15、用户web层服务(三)
    解决Windows Server 2022启动PowerShell出现乱码问题
    企业应用超融合架构的设计实例及超融合应用场景分析
    ElasticSearch入门
    Appium自动化环境搭建保姆级教程
    python目录树生成器
  • 原文地址:https://blog.csdn.net/qq_41767116/article/details/126873418