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

Golang 并发机制-5:详解syn包同步原语

并发性是现代软件开发的一个基本方面,Go(也称为Golang)为并发编程提供了一组健壮的工具。Go语言中用于管理并发性的重要包之一是“sync”包。在本文中,我们将概述“sync”包,并深入研究其最重要的同步原语之一:Wait
Groups.

sync 包概述

sync包是Go中的一个标准库包,为并发编程提供同步原语。它为开发人员提供了协调和同步程序的工具,确保安全有序地执行并发任务。sync包提供的一些关键同步原语包括Mutexes, RWMutexes, Cond, Wait Groups。

Wait Groups

Wait Group是由Go中的“sync”包提供的同步原语。它是一个简单但功能强大的工具,用于管理goroutine的同步,特别是当你希望等待一组goroutine在继续之前完成它们的任务时。

当有多个并发执行独立任务的goroutine,并且你需要确保它们在继续执行主程序之前都已完成执行时,等待组是有用的。
在这里插入图片描述

让我们通过一个代码示例来探索如何使用Wait Groups:

package mainimport ("fmt""sync""time"
)func worker(id int, wg *sync.WaitGroup) {defer wg.Done() // Decrement the Wait Group counter when donefmt.Printf("Worker %d is working\n", id)time.Sleep(time.Second)fmt.Printf("Worker %d has finished\n", id)
}func main() {var wg sync.WaitGroupfor i := 1; i <= 3; i++ {wg.Add(1) // Increment the Wait Group counter for each Goroutinego worker(i, &wg)}wg.Wait() // Wait for all Goroutines to finishfmt.Println("All workers have finished.")
}

在这个例子中,我们定义了一个worker函数,它通过睡眠一秒钟来模拟工作。我们启动三个goroutine,每个代表一个worker,并使用sync。来协调他们的执行。

  • wg.Add(1)在启动每个例程之前增加等待组计数器。
  • wg.Done()worker函数中被延迟,以在gooutine完成其工作时减少计数器。
  • wg.Wait()阻塞主程序,直到所有的例程都完成,确保我们等待所有工人的完成。

RWMutex

RWMutex(读写互斥)是Go语言中的一个同步原语,它允许多个线程同时读取共享数据,同时确保对写入的独占访问。它在经常读取数据但不经常修改数据的场景中非常有用。

下面是一个演示如何使用RWMutex的简单示例:

package mainimport ("fmt""sync""time"
)var (data        intdataMutex   sync.RWMutex
)func readData() int {dataMutex.RLock() // Read Lockdefer dataMutex.RUnlock()return data
}func writeData(value int) {dataMutex.Lock() // Write Lockdefer dataMutex.Unlock()data = value
}func main() {// Read data concurrentlyfor i := 1; i <= 5; i++ {go func() {fmt.Println("Read Data:", readData())}()}// Write datawriteData(42)time.Sleep(time.Second)
}

在这个例子中,多个Goroutine并发地读取共享的“数据”,并且一个单独的Goroutine写入它。RWMutex确保多个读取器可以同时访问数据,但一次只有一个写入器可以修改数据。

什么是条件变量?

在 Go 语言里,条件变量(sync.Cond)是一种同步原语,它用于协调多个 goroutine 的执行顺序,尤其是在某个条件满足时唤醒等待的 goroutine。条件变量通常和互斥锁(sync.Mutexsync.RWMutex)一起使用,互斥锁用于保护共享资源,而条件变量则用于在共享资源的状态发生变化时通知等待的 goroutine。

主要特性
1. 等待(Wait)

Cond.Wait() 方法会让当前 goroutine 进入等待状态,并且会自动释放与之关联的互斥锁。当其他 goroutine 调用 Cond.Signal()Cond.Broadcast() 唤醒它时,该 goroutine 会重新获取互斥锁并继续执行。

2. 单发通知(Signal)

Cond.Signal() 方法会唤醒一个正在等待该条件变量的 goroutine。如果有多个 goroutine 在等待,它会选择其中一个进行唤醒。

3. 广播通知(Broadcast)

Cond.Broadcast() 方法会唤醒所有正在等待该条件变量的 goroutine。

条件变量(Condition Variables)是同步原语,它允许程序在继续之前等待特定条件变为真。当你需要根据特定条件协调多个goroutine的执行时,它们很有帮助。

下面是一个说明条件变量使用的基本示例:

package mainimport ("fmt""sync""time"
)var (conditionMutex sync.Mutexcondition      *sync.CondisReady        bool
)func waitForCondition() {conditionMutex.Lock()defer conditionMutex.Unlock()for !isReady {fmt.Println("Waiting for the condition...")condition.Wait()}fmt.Println("Condition met, proceeding.")
}func setCondition() {time.Sleep(2 * time.Second)conditionMutex.Lock()isReady = truecondition.Signal() // Signal one waiting GoroutineconditionMutex.Unlock()
}func main() {condition = sync.NewCond(&conditionMutex)go waitForCondition()go setCondition()time.Sleep(5 * time.Second)
}

在这个例子中,一个Goroutine使用condition. wait()等待条件变为真,而另一个Goroutine将条件设置为true,并使用condition. signal()向等待的Goroutine发出信号。

下面是一个简单的示例,模拟生产者 - 消费者模型,使用条件变量来协调生产者和消费者的行为:

package mainimport ("fmt""sync""time"
)// 定义一个缓冲区和相关的锁与条件变量
var (buffer    []intbufferLen = 5mutex     sync.Mutexcond      = sync.NewCond(&mutex)
)// 生产者函数
func producer(id int) {for {mutex.Lock()// 检查缓冲区是否已满for len(buffer) == bufferLen {fmt.Printf("Producer %d is waiting as buffer is full...\n", id)cond.Wait() // 缓冲区满,等待消费者消费}// 生产一个元素item := len(buffer) + 1buffer = append(buffer, item)fmt.Printf("Producer %d produced item %d. Buffer: %v\n", id, item, buffer)cond.Signal() // 通知可能正在等待的消费者mutex.Unlock()time.Sleep(time.Second)}
}// 消费者函数
func consumer(id int) {for {mutex.Lock()// 检查缓冲区是否为空for len(buffer) == 0 {fmt.Printf("Consumer %d is waiting as buffer is empty...\n", id)cond.Wait() // 缓冲区空,等待生产者生产}// 消费一个元素item := buffer[0]buffer = buffer[1:]fmt.Printf("Consumer %d consumed item %d. Buffer: %v\n", id, item, buffer)cond.Signal() // 通知可能正在等待的生产者mutex.Unlock()time.Sleep(time.Second)}
}func main() {// 启动生产者和消费者 goroutinego producer(1)go consumer(1)// 让程序运行一段时间time.Sleep(10 * time.Second)
}

通过使用条件变量,生产者和消费者能够在合适的时机进行等待和唤醒,确保缓冲区不会溢出或空消费。

原子操作

原子操作(Atomic Operations )是作为单个、不可分割的工作单元执行的操作。它们通常用于在不需要互斥锁的情况下安全地更新并发程序中的共享变量。Go为原子操作提供了一个名为“atomic”的包。

下面是演示原子操作的例子:

package mainimport ("fmt""sync""sync/atomic""time"
)var (counter int32wg      sync.WaitGroup
)func incrementCounter() {defer wg.Done()for i := 0; i < 100000; i++ {atomic.AddInt32(&counter, 1)}
}func main() {wg.Add(2)go incrementCounter()go incrementCounter()wg.Wait()fmt.Println("Counter:", atomic.LoadInt32(&counter))
}

在这个例子中,两个线程使用原子操作增加共享的“计数器”变量。atomic.AddInt32函数确保增量操作是原子性的,并且对于并发访问是安全的。

选择正确的同步机制

在选择正确的同步机制时,请考虑以下指导原则:

  • 当需要细粒度的访问控制时,互斥锁(RWMutex用于读,Mutex用于写)适用于保护共享数据。
  • 当需要根据特定条件协调程序时,条件变量很有价值。
  • 当希望避免互斥锁的开销时,原子操作对于对共享变量进行简单操作是有效的。
  • 始终选择最适合您特定用例需求的同步机制。

总之,Go在“sync”包和原子操作中提供了一套通用的同步机制,用于管理对共享资源的并发访问。了解这些工具并根据您的并发需求选择合适的工具对于编写高效可靠的并发Go程序至关重要。

相关文章:

Golang 并发机制-5:详解syn包同步原语

并发性是现代软件开发的一个基本方面&#xff0c;Go&#xff08;也称为Golang&#xff09;为并发编程提供了一组健壮的工具。Go语言中用于管理并发性的重要包之一是“sync”包。在本文中&#xff0c;我们将概述“sync”包&#xff0c;并深入研究其最重要的同步原语之一&#xf…...

实验六 项目二 简易信号发生器的设计与实现 (HEU)

声明&#xff1a;代码部分使用了AI工具 实验六 综合考核 Quartus 18.0 FPGA 5CSXFC6D6F31C6N 1. 实验项目 要求利用硬件描述语言Verilog&#xff08;或VHDL&#xff09;、图形描述方式、IP核&#xff0c;结合数字系统设计方法&#xff0c;在Quartus开发环境下&#xff…...

如何用微信小程序写春联

​ 生活没有模板,只需心灯一盏。 如果笑能让你释然,那就开怀一笑;如果哭能让你减压,那就让泪水流下来。如果沉默是金,那就不用解释;如果放下能更好地前行,就别再扛着。 一、引入 Vant UI 1、通过 npm 安装 npm i @vant/weapp -S --production​​ 2、修改 app.json …...

LabVIEW无人机航线控制系统

介绍了一种无人机航线控制系统&#xff0c;该系统利用LabVIEW软件与MPU6050九轴传感器相结合&#xff0c;实现无人机飞行高度、速度、俯仰角和滚动角的实时监控。系统通过虚拟仪器技术&#xff0c;有效实现了数据的采集、处理及回放&#xff0c;极大提高了无人机航线的控制精度…...

C++哈希表深度解析:从原理到实现,全面掌握高效键值对存储

目录 一、核心组件与原理 1. 哈希函数&#xff08;Hash Function&#xff09; 2. 冲突解决&#xff08;Collision Resolution&#xff09; 3. 负载因子&#xff08;Load Factor&#xff09;与扩容 二、C实现&#xff1a;std::unordered_map 1. 模板参数 2. 关键操作与复…...

Vue.js组件开发-实现字母向上浮动

使用Vue实现字母向上浮动的效果 实现步骤 创建Vue项目&#xff1a;使用Vue CLI来创建一个新的Vue项目。定义组件结构&#xff1a;在组件的模板中&#xff0c;定义包含字母的元素。添加样式&#xff1a;使用CSS动画来实现字母向上浮动的效果。绑定动画类&#xff1a;在Vue组件…...

自研有限元软件与ANSYS精度对比-Bar2D2Node二维杆单元模型-四连杆实例

目录 1、四连杆工程实例以及手算求解 2、四连杆的自研有限元软件求解 2.1、选择单元类型 2.2、导入四连杆工程 2.3、节点坐标定义 2.4、单元连接关系、材料定义 2.5、约束定义 2.6、外载定义 2.7、矩阵求解 2.8、变形云图展示 2.9、节点位移 2.10、单元应力 2.11、…...

04树 + 堆 + 优先队列 + 图(D1_树(D11_伸展树))

目录 一、基本介绍 二、伸展操作 1. 左右情况的伸展 2. 左左情况的伸展 3. 右左情况的伸展 4. 右右情况的伸展 三、其它操作 1. 插入 2. 删除 四、代码实现 一、基本介绍 伸展树是一种二叉搜索树&#xff0c;伸展树也是一种平衡树&#xff0c;不过伸展树并不像AVL树那…...

c语言练习题【数据类型、递归、双向链表快速排序】

练习1&#xff1a;数据类型 请写出以下几个数据的数据类型 整数 a a 的地址 存放a的数组 b 存放a的地址的数组 b的地址 c的地址 指向 printf 函数的指针 d 存放 d的数组 整数 a 的类型 数据类型是 int a 的地址 数据类型是 int*&#xff08;指向 int 类型的指针&#xff09; …...

SliverAppBar的功能和用法

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverGrid组件相关的内容&#xff0c;本章回中将介绍SliverAppBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverAppBar和普通的AppBar类似&#xff0c;它们的…...

五、定时器实现呼吸灯

5.1 定时器与计数器简介 定时器是一种通过对内部时钟脉冲计数来测量时间间隔的模块。它的核心是一个递增或递减的寄存器&#xff08;计数器值&#xff09;。如果系统时钟为 1 MHz&#xff0c;定时器每 1 μs 计数一次。 计数器是一种对外部事件&#xff08;如脉冲信号&#xff…...

Elasticsearch的索引生命周期管理

目录 说明零、参考一、ILM的基本概念二、ILM的实践步骤Elasticsearch ILM策略中的“最小年龄”是如何计算的&#xff1f;如何监控和调整Elasticsearch ILM策略的性能&#xff1f; 1. **监控性能**使用/_cat/thread_pool API基本请求格式请求特定线程池的信息响应内容 2. **调整…...

【大模型理论篇】最近大火的DeepSeek-R1初探系列1

1. 背景介绍 这一整个春节&#xff0c;被DeepSeek-R1刷屏。各种铺天盖地的新闻以及老板发的相关信息&#xff0c;着实感受到DeepSeek-R1在国外出圈的震撼。 DeepSeek推出了新的推理模型&#xff1a;DeepSeek-R1-Zero 和 DeepSeek-R1。DeepSeek-R1-Zero 是一个在没有经过监督微调…...

【数据结构】(4) 线性表 List

一、什么是线性表 线性表就是 n 个相同类型元素的有限序列&#xff0c;每一个元素只有一个前驱和后继&#xff08;除了第一个和最后一个元素&#xff09;。 数据结构中&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列。 二、什么是 List List 是 Java 中的线性…...

【C++ STL】vector容器详解:从入门到精通

【C STL】vector容器详解&#xff1a;从入门到精通 摘要&#xff1a;本文深入讲解C STL中vector容器的使用方法&#xff0c;涵盖常用函数、代码示例及注意事项&#xff0c;助你快速掌握动态数组的核心操作&#xff01; 一、vector概述 vector是C标准模板库&#xff08;STL&am…...

OpenAI推出Deep Research带给我们怎样的启示

OpenAI 又发新产品了&#xff0c;这次是面向深度研究领域的智能体产品 ——「Deep Research」&#xff0c;貌似被逼无奈的节奏… 在技术方面&#xff0c;Deep Research搭载了优化后o3模型并通过端到端强化学习在多个领域的复杂浏览和推理任务上进行了训练。因没有更多的技术暴露…...

洛谷[USACO08DEC] Patting Heads S

题目传送门 题目难度&#xff1a;普及/提高一 题面翻译 今天是贝茜的生日&#xff0c;为了庆祝自己的生日&#xff0c;贝茜邀你来玩一个游戏。 贝茜让 N N N ( 1 ≤ N ≤ 1 0 5 1\leq N\leq 10^5 1≤N≤105) 头奶牛坐成一个圈。除了 1 1 1 号与 N N N 号奶牛外&#xff0…...

CSS 溢出内容处理:从基础到实战

CSS 溢出内容处理&#xff1a;从基础到实战 1. 什么是溢出&#xff1f;示例代码&#xff1a;默认溢出行为 2. 使用 overflow 属性控制溢出2.1 使用 overflow: hidden 裁剪内容示例代码&#xff1a;裁剪溢出内容 2.2 使用 overflow: scroll 显示滚动条示例代码&#xff1a;显示滚…...

Spring Boot项目如何使用MyBatis实现分页查询

写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油&#xff0c;冲鸭&#x…...

飞行汽车中的无刷外转子电机、人形机器人中的无框力矩电机技术解析与应用

重点:无刷外转子电机与无框力矩电机&#xff1a;技术解析与应用对比 在现代工业自动化和精密机械领域&#xff0c;无刷电机因其高效、低噪音和高可靠性而备受青睐。其中&#xff0c;无刷外转子电机和无框力矩电机更是以其独特的结构和性能特点&#xff0c;成为众多应用场景中的…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...