• golang 协程并发代码 demo


    有时我们可能想既在外层循环中实现多协程并发,还想在内层循环中实现多协程并发,那么我们需要同时在内层和外层使用 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? 如何限定数量?

  • 相关阅读:
    Petapoco 数据库操作类
    .net Cookie操作公共方法 CookieHelper
    .net 服务端缓存 Cache/CacheHelper
    Base64加密解密方法
    对多字段进行去重 ( Linq 方式 )
    BootStrap之 提示工具(Tooltip)插件
    bootstrap之弹出框
    Jquery 强大的表单验证操作
    强大的数据库工具 dbForge Studio ForMySql
    My操作小技巧
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/16696394.html
Copyright © 2020-2023  润新知