当前位置: 首页 > article >正文

【Golang】WaitGroup 实现原理

文章目录

  • 前言
  • 一、介绍
  • 二、实现原理
  • 三、使用方式
  • 四、总结


前言

在并发编程中,协调多个 goroutine 的执行顺序和同步是一个常见的需求。Golang 提供了 sync.WaitGroup 来简化这一过程。WaitGroup 允许主 goroutine 等待一组 goroutine 完成工作。本文将详细介绍 sync.WaitGroup 的实现原理及其使用方法,帮助读者更好地理解和应用这一工具。


一、介绍

1. 什么是 sync.WaitGroup
sync.WaitGroup 是 Golang 标准库中的一个同步原语,用于等待一组 goroutine 完成。它提供了一种简单的方式来协调多个 goroutine 的执行顺序,确保主 goroutine 在所有子 goroutine 完成后再继续执行。

2. sync.WaitGroup 的基本结构
sync.WaitGroup 的核心是一个计数器和一个条件变量。计数器记录需要等待的 goroutine 数量,条件变量用于在计数器变为零时通知等待的 goroutine。

WaitGroup 的结构体定义如下:

type WaitGroup struct {
    noCopy noCopy
    state1 [3]uint32
}

state1 数组包含了三个字段:

  • counter:计数器,记录需要等待的 goroutine 数量。
  • waiters:等待的 goroutine 数量。
  • sema:信号量,用于通知等待的 goroutine。

二、实现原理

1. Add 方法
Add 方法用于增加或减少计数器的值。正数表示增加需要等待的 goroutine 数量,负数表示减少。

示例:

func (wg *WaitGroup) Add(delta int) {
    statep := &wg.state1[0]
    state := atomic.AddUint32(statep, uint32(delta)<<1)
    v := int32(state >> 1)
    if v < 0 {
        panic("sync: negative WaitGroup counter")
    }
    if delta > 0 && v == int32(delta) {
        return
    }
    if delta < 0 && v == 0 {
        for i := 0; i < int(state&1); i++ {
            runtime_Semrelease(&wg.state1[2], false, 0)
        }
    }
}

2. Done 方法
Done 方法用于减少计数器的值,相当于 Add(-1)。当计数器变为零时,通知所有等待的 goroutine。

示例:

func (wg *WaitGroup) Done() {
    wg.Add(-1)
}

3. Wait 方法
Wait 方法用于等待计数器变为零。当计数器为零时,Wait 方法立即返回;否则,当前 goroutine 会被阻塞,直到计数器变为零。

示例:

func (wg *WaitGroup) Wait() {
    statep := &wg.state1[0]
    if atomic.LoadUint32(statep)>>1 == 0 {
        return
    }
    runtime_Semacquire(&wg.state1[2])
}

三、使用方式

1. 基本使用
sync.WaitGroup 的基本使用方法包括以下几个步骤:

  • 创建一个 WaitGroup 实例。
  • 使用 Add 方法设置需要等待的 goroutine 数量。
  • 在每个 goroutine 中调用 Done 方法,表示完成工作。
  • 在主 goroutine 中调用 Wait 方法,等待所有子 goroutine 完成。
    示例:
package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers done")
}

2. 注意事项

  • WaitGroup 的计数器不能为负数。如果调用 Add 方法时传入的负数使计数器变为负数,会引发 panic。
  • WaitGroup 不能被复制。应始终传递指向 WaitGroup 的指针,以确保所有 goroutine 操作的是同一个 WaitGroup 实例。

四、总结

sync.WaitGroup 是 Golang 中用于协调多个 goroutine 执行顺序的强大工具。通过理解 WaitGroup 的实现原理和使用方法,开发者可以更好地管理并发任务,确保主 goroutine 在所有子 goroutine 完成后再继续执行。希望通过本文的介绍,读者能够深入了解 sync.WaitGroup 的实现原理及其使用方法,并在实际项目中灵活运用。


http://www.kler.cn/a/421334.html

相关文章:

  • 在鲲鹏麒麟服务器上部署MySQL主从集群
  • 【ArkTS】使用AVRecorder录制音频 --内附录音机开发详细代码
  • 自然语言处理:基于BERT预训练模型的中文命名实体识别(使用PyTorch)
  • 【QNX+Android虚拟化方案】132 - QNX 系统内存、CPU负载监控
  • Meta-Llama-3-8B-Instruct 模型的混合精度训练显存需求:AdamW优化器(中英双语)
  • Linux 各个目录作用
  • 解决el-select数据量过大的3种方法
  • nerdctl:与 Docker 兼容的 containerd CLI
  • ArcMap 多图层叠加表达变化等功能操作
  • 21天掌握javaweb--->第3天:MyBatis基础与Spring Boot集成
  • MATLAB基础应用精讲-【人工智能】数据生命周期‌(概念篇)
  • 【jvm】C1编译器
  • NLP-语料库的相关知识整理
  • vue 项目准备
  • Figma入门-组件变体复习
  • Kafka 数据写入问题
  • linux安全-firewalld防火墙-基础讲解
  • Linux Find 命令详情解释
  • cf EC 172 C(0->-1 的转化+区间和使用前缀和表示,化简式子)+ D(二维的信息,先对一维排序,另一维看情况分析)
  • 时间同步服务器--Linux中
  • leetcode--螺旋矩阵
  • 《利用 Python 和 Pyecharts 对豆瓣电影数据可视化分析》
  • 「Java EE开发指南」如何在Java EE网站中使用CodeLive?
  • mysql-为什么需要线程池
  • 爬虫获取的数据如何确保准确性?
  • CAD 二次开发入门与实践:以 C# 为例