Bruce Blog Bruce Blog
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航

Bruce Tao

运维界的该溜子
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航
  • 基础

  • Go进阶

    • Go进阶
    • File操作
    • IO操作
    • 文件复制
    • 断点续传
    • bufio包
    • ioutil包
    • 遍历目录
    • 并发性Concurrency概念
    • Goroutine初识
    • Goroutine并发模型
    • Runtime包
    • 临界资源安全问题
    • sync包WaitGroup
      • 互斥锁
      • 读写锁
      • Channel通道
      • 关闭通道和通道上范围循环
      • 缓冲通道
      • 定向通道
      • time包中的通道相关函数
      • select语句
      • CSP并发模型
      • Go语言反射(一)
      • Go语言反射(二)
    • Go框架

    • Golang辅助

    • Golang
    • Go进阶
    Bruce
    2022-12-03
    目录

    sync包WaitGroup

    # 一、sync包 ---WaitGroup

    • https://golang.google.cn/pkg/sync/

    官方文件sync的介绍

    Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication
    
    1

    image-20221123233942416

    sync是synchronization同步这个词的缩写,所以也会叫做同步包.这里提供了基本同步的操作,比如互斥锁等等.这里除了Once和WaitGroup类型之外,大多数类型都是供低级库例教程使用的.更高级别同步最好通过channel通道和communication通信来完成

    image-20221123234346232

    # 一、WaitGoup

    WaitGroup,同步等待组.

    在类型上,它是一个结构体.一个WaitGroup的用途是等待一个goroutine的集合执行完成.主要goroutine调用了Add()方法来设置要等待的goroutine的数量.然后,每个goroutine都会执行并且执行完成后调用Done()这个方法.与此同时,可以使用Wait()方法来阻塞,知道所有goroutine多执行完成.

    # 二、Add()方法

    Add这个方法,用来设置到WaitGroup的计数器的值.可以理解为每个waitgroup中都有一个计数器用来表示这个同步等待组中要执行的goroutine的数量.

    如果计数器的数值变为0,那么就表示等待时被阻塞的goroutine都被释放,如果计数器的数值为负数,那么就会引发恐慌,程序就报错了.

    image-20221123234924644

    func (wg *WaitGroup) Add(delta int) {
    	statep, semap := wg.state()
    	if race.Enabled {
    		_ = *statep // trigger nil deref early
    		if delta < 0 {
    			// Synchronize decrements with Wait.
    			race.ReleaseMerge(unsafe.Pointer(wg))
    		}
    		race.Disable()
    		defer race.Enable()
    	}
    	state := atomic.AddUint64(statep, uint64(delta)<<32)
    	v := int32(state >> 32)
    	w := uint32(state)
    	if race.Enabled && delta > 0 && v == int32(delta) {
    		// The first increment must be synchronized with Wait.
    		// Need to model this as a read, because there can be
    		// several concurrent wg.counter transitions from 0.
    		race.Read(unsafe.Pointer(semap))
    	}
    	if v < 0 {
    		panic("sync: negative WaitGroup counter")
    	}
    	if w != 0 && delta > 0 && v == int32(delta) {
    		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
    	}
    	if v > 0 || w == 0 {
    		return
    	}
    	// This goroutine has set counter to 0 when waiters > 0.
    	// Now there can't be concurrent mutations of state:
    	// - Adds must not happen concurrently with Wait,
    	// - Wait does not increment waiters if it sees counter == 0.
    	// Still do a cheap sanity check to detect WaitGroup misuse.
    	if *statep != state {
    		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
    	}
    	// Reset waiters count to 0.
    	*statep = 0
    	for ; w != 0; w-- {
    		runtime_Semrelease(semap, false, 0)
    	}
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43

    # 三、Done()方法

    Done()方法,就是当WaitGroup同步等待中的某个goroutine执行完毕后,设置这个WaitGroup的counter数值减1.

    image-20221123235055298

    其实Done()底层代码就是调用了Add()方法:

    // Done decrements the WaitGroup counter by one.
    func (wg *WaitGroup) Done() {
    	wg.Add(-1)
    }
    
    1
    2
    3
    4

    # 四、Wait()方法

    Wait()方法,表示让当前的goroutine等待,进入阻塞状态.一直到WaitGroup的计数器为零.才能解除阻塞,这个goroutine才能继续执行.

    image-20221123235305334

    # 五、示例代码

    创建并启动两个goroutine,来打印数字和字母,并在main goroutine中,将这两个子goroutine加入到一个WaitGroup中,同时让main goroutine进入Wait(),让两个子goroutine先执行.当每个goroutine执行完毕之后,调用Done()方法,设置WaitGroup的counter减1。当两条子goroutine都执行完毕后,WaitGroup中的counter的数值为零,解除main goroutine的阻塞.

    示例代码

    package main
    
    import (
        "fmt"
        "sync"
    )
    var wg sync.WaitGroup // 创建同步等待组对象
    func main()  {
        /*
        WaitGroup:同步等待组
            可以使用Add(),设置等待组中要 执行的子goroutine的数量,
            
            在main 函数中,使用wait(),让主程序处于等待状态。直到等待组中子程序执行完毕。解除阻塞
    
            子gorotuine对应的函数中。wg.Done(),用于让等待组中的子程序的数量减1
         */
        //设置等待组中,要执行的goroutine的数量
        wg.Add(2)
        go fun1()
        go fun2()
        fmt.Println("main进入阻塞状态。。。等待wg中的子goroutine结束。。")
        wg.Wait() //表示main goroutine进入等待,意味着阻塞
        fmt.Println("main,解除阻塞。。")
    
    }
    func fun1()  {
        for i:=1;i<=10;i++{
            fmt.Println("fun1.。。i:",i)
        }
        wg.Done() //给wg等待中的执行的goroutine数量减1.同Add(-1)
    }
    func fun2()  {
        defer wg.Done()
        for j:=1;j<=10;j++{
            fmt.Println("\tfun2..j,",j)
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    image-20221124145456553

    上次更新: 2024/04/09, 16:48:42
    临界资源安全问题
    互斥锁

    ← 临界资源安全问题 互斥锁→

    最近更新
    01
    AWS NAT-NetWork-Firwalld配置(一)
    04-09
    02
    AWS NAT-NetWork-Firwalld配置(二)
    04-09
    03
    kubernetes部署minio对象存储
    01-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Bruce Tao Blog Space | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式