go语言进阶之同步原语

同步原语

资源竞争

定义与实现

在Go语言中,资源竞争指多个goroutine同时访问共享资源,导致程序的行为不可预测或者不一致。

资源竞争通常发生在对同一变量进行读写操作时,如果没有正确的同步机制来控制访问可能会引发资源竞争

package mainimport ("fmt""sync"
)var counter int // 共享资源func increment(wg *sync.WaitGroup) {defer wg.Done()counter++
}func main() {var wg sync.WaitGroupfor i := 0; i < 1000; i++ {wg.Add(1)go increment(&wg)}wg.Wait()fmt.Println("Final counter:", counter) // 可能不是 1000
}

![[Pasted image 20241029003944.png]]
可以运行后看到发生了资源竞争,导致不为1000。

原因

  1. 多个goroutine同时写入或读取共享资源,缺乏恰当的同步机制
  2. 非原子操作,对共享变量的操作如果不是原子的,会导致在操作过程中被其他goroutine中断,导致数据错误

与安全的关系

  1. 可能会导致数据一致性问题,影响应用数据
  2. 并发攻击,比如对ddos可以利用并发性来压垮系统,导致资源竞争和其他问题。
  3. 状态泄露,如果资源竞争导致应用状态不一样,可能可以利用这些漏洞来获取敏感信息或执行恶意操作。

同步原语

同步原语用于控制多个goroutine之间的访问顺序和协调,正好可以解决上面的资源竞争问题。

互斥锁(sync.Mutex)

确保同一时间只有一个goroutine可以访问资源

实现

package main  import (  "fmt"  "sync")  var (  mu      sync.Mutex  counter int  
)  func increment() {  mu.Lock()   //加锁  counter++   //访问共享资源  mu.Unlock() //解锁  
}  func main() {  for i := 1; i <= 1000; i++ {  increment()  }  fmt.Println(counter)  }

可以看到现在输出为1000

![[Pasted image 20241029011834.png]]

sync.RWMutex

RWMutex是Go语言的读写互斥锁,用于处理读多写少的场景,他允许多个goroutine并发地读取共享资源,但是写操作时之允许一个goroutine进行写操作。

package main  import (  "fmt"  "sync")  var (  rwmu    sync.RWMutex // 创建读写互斥锁  counter int          // 共享计数器  
)  func read(wg *sync.WaitGroup) {  defer wg.Done()                  // 完成时通知 WaitGroup    rwmu.RLock()                     // 获取读锁  fmt.Println("Counter:", counter) // 读取共享资源  rwmu.RUnlock()                   // 释放读锁  
}  func write(wg *sync.WaitGroup) {  defer wg.Done() // 完成时通知 WaitGroup    rwmu.Lock()     // 获取写锁  counter++       // 修改共享资源  rwmu.Unlock()   // 释放写锁  
}  func main() {  var wg sync.WaitGroup  // 启动多个读和写的 goroutine    for i := 0; i < 5; i++ {  wg.Add(1)  go read(&wg) // 启动读取 goroutine    }  for i := 0; i < 5; i++ {  wg.Add(1)  go write(&wg) // 启动写入 goroutine    }  wg.Wait() // 等待所有 goroutine 完成  
}

这个程序由于read在write前所以可以更好的体现read和write是同时进行的

输出为

![[Pasted image 20241029014147.png]]

这个的输出不固定,因为无法确定程序每一次的执行速度。

sync.WaitGroup

WaiGroup 常用于等待一组goroutine完成,它可以让主goroutine等待其他多个goroutine的完成

package mainimport ("fmt""sync""time"
)func worker(id int, wg *sync.WaitGroup) {defer wg.Done() // 在函数结束时调用 Done()fmt.Printf("Worker %d is working...\n", id)time.Sleep(1 * time.Second) // 模拟一些工作fmt.Printf("Worker %d is done.\n", id)
}func main() {var wg sync.WaitGroupfor i := 1; i <= 5; i++ {wg.Add(1) // 增加 WaitGroup 计数go worker(i, &wg) // 启动 goroutine}wg.Wait() // 等待所有 goroutine 完成fmt.Println("All workers are done.")
}

这个函数主要的作用就是等待所有线程执行完再结束主线程,如果当主线程提前结束,其他线程就算没有完成执行操作也无法继续执行了

sync.Once

Once函数和它的名字一样,主要作用就是确保某段代码只执行一次,无论有多少个goroutine尝试调用它,都只执行一次。

package mainimport ("fmt""sync"
)var once sync.Oncefunc initialize() {fmt.Println("正在初始化...")
}func worker(id int) {// 仅调用一次初始化函数once.Do(initialize)fmt.Printf("工作者 %d 正在工作\n", id)
}func main() {var wg sync.WaitGroupfor i := 1; i <= 5; i++ {wg.Add(1)go func(id int) {defer wg.Done()worker(id)}(i)}wg.Wait() // 等待所有 goroutine 完成fmt.Println("所有工作者完成")
}

这段代码运行后可以发现,初始化操作只运行了一次,当有资源初始化等操作时,使用Once函数是一个不错的选择。

sync.Cond

Cond函数是一个用于实现条件变量的同步原语。它通常和Mutex和RWMutex一起使用,允许goroutines在特定条件下进行等待和通知

package mainimport ("fmt""sync""time"
)// Resource 结构体包含一个互斥锁和一个条件变量
type Resource struct {mu    sync.Mutex   // 用于保护共享资源的互斥锁cond  *sync.Cond   // 条件变量,用于协程之间的同步value int          // 共享资源的值
}// NewResource 创建一个新的 Resource 实例
func NewResource() *Resource {r := &Resource{}r.cond = sync.NewCond(&r.mu) // 初始化条件变量,关联互斥锁return r
}// SetValue 设置资源的值,并通知等待的协程
func (r *Resource) SetValue(val int) {r.mu.Lock()         // 获取互斥锁r.value = val       // 设置资源的值r.cond.Broadcast()  // 唤醒所有等待的协程r.mu.Unlock()       // 释放互斥锁
}// GetValue 获取资源的值,如果值为0则等待
func (r *Resource) GetValue() int {r.mu.Lock()                       // 获取互斥锁for r.value == 0 {                // 如果值为0,则等待r.cond.Wait()                 // 等待条件变量信号}val := r.value                    // 获取资源的值r.mu.Unlock()                     // 释放互斥锁return val                        // 返回获取的值
}func main() {resource := NewResource() // 创建一个新的资源实例// 启动一个协程,设置资源的值go func() {time.Sleep(1 * time.Second) // 等待1秒以确保 GetValue 先调用fmt.Println("设置值为42")resource.SetValue(42) // 设置值为42,并通知等待的协程}()// 主协程获取资源的值val := resource.GetValue() // 获取值fmt.Printf("获取的值是: %d\n", val) // 打印获取的值
}

这个函数主要的作用就是使用Wait方法阻塞协程,然后用Signal()或Broadcast()方法唤醒一个等待时间最长的协程;或者唤醒全部正在等待的协程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/3927.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Hunyuan-Large:腾讯发布业界参数规模最大的开源 MoE 模型,支持超长文本输入,超越主流开源模型

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; &#x1f966; 微信公众号&#xff…

Linux基础

1. openssl passwd -1 密码 128位 openssl passwd -5 密码&#xff08;更安全&#xff09;256位 openssl是开源的加密工具包&#xff0c;有各种加密&#xff0c;解密等功能 2. 文件管理 创建空文件 touch newfile 删除文件 rm new file 新建日录 mkdir newdir 删除…

HuggingFace情感分析任务微调

官方教程地址&#xff1a;https://huggingface.co/learn/nlp-course/zh-CN/chapter3/1?fwpt 部分内容参考&#xff1a; 李福林, & 计算机技术. (2023). HuggingFace 自然语言处理详解: 基于 BERT 中文模型的任务实战. 清华大学出版社. HuggingFace将AI项目研发分为四个步骤…

Springboot——对接支付宝实现扫码支付

文章目录 前言官方文档以及说明1、申请沙箱2、进入沙箱获取对应的关键信息3、拿到系统生成的公钥和密钥 注意事项创建springboot项目1、引入依赖2、配置连接参数3、创建配置类&#xff0c;用于接收这些参数4、中间类的定义(订单类)5、编写测试接口场景一、pc端请求后端后&#…

迪杰斯特拉算法

迪杰斯特拉算法 LeetCode 743. 网络延迟时间 https://blog.csdn.net/xiaoxi_hahaha/article/details/110257368 import sysdef dijkstra(graph, source):"""dijkstra算法:param graph: 邻接矩阵:param source: 出发点&#xff0c;源点:return:""&…

STL学习-容器适配器

一.stack栈 1.栈的介绍 stack 栈是一种只在一端(栈顶)进行数据插入(入栈)和删除(出栈)的数据结构,它满足后进 先出(LIFO)的特性。 使用push(入栈)将数据放入stack,使用pop(出栈)将元素从容器中移除。 栈的结构如图&#xff1a; 在头文件<stack>中&#xff0c;class st…

【C语言】动态内存开辟

写在前面 C语言中有不少开辟空间的办法&#xff0c;但是在堆上开辟的方法也就只有动态内存开辟&#xff0c;其访问特性与数组相似&#xff0c;但最大区别是数组是开辟在栈上&#xff0c;而动态内存开辟是开辟在堆上的。这篇笔记就让不才娓娓道来。 PS:本篇没有目录实在抱歉CSD…

海的记忆:海滨学院班级回忆录项目

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

【VScode】C/C++多文件夹下、多文件引用、分别编译——仅一个设置【适合新人入手】

【VScode】C/C多文件夹内的多文件引用编译 1、问题2、前提&#xff08;最简环境&#xff09;3、核心&#xff08;关键配置&#xff09;4、成功享用~ 1、问题 在使用 VScode 编写一个简单项目的时候&#xff0c;没有特别配置的情况下&#xff0c;若主文件(.c)引用了自定义的头文…

62 mysql 中 存储引擎MyISAM 中索引的使用

前言 固定数据表 mysql. tables_priv 的表结构创建如下 CREATE TABLE tables_priv (Host char(60) COLLATE utf8_bin NOT NULL DEFAULT ,Db char(64) COLLATE utf8_bin NOT NULL DEFAULT ,User char(32) COLLATE utf8_bin NOT NULL DEFAULT ,Table_name char(64) COLLATE u…

使用buildx构建多架构平台镜像

1. 查看buildx插件信息 比较新的docker-ce版本默认已经集成了buildx插件 [rootdocker ~]# docker buildx version github.com/docker/buildx v0.11.2 9872040 [rootdocker ~]#2. 增加多平台镜像构建支持 通过tonistiigi/binfmt:latest初始化一个基于容器的构建环境&#xff…

数据库基础(3) . Navicat使用

0.下载安装 官网 : https://www.navicat.com.cn/ Navicat 中国 | 支持 MySQL、Redis、MariaDB、MongoDB、SQL Server、SQLite、Oracle 和 PostgreSQL 的数据库管理 1.连接数据库 1.1.连接 1.1.1.点击连接 打开navicat 点击 左上角连接 1.1.2.选择MySQL 弹出配置界面 1.1…

MySQL(上)

一、SQL优化 1、如何定位及优化SQL语句的性能问题&#xff1f;创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因&#xff1f; 对于性能比较低的sql语句定位&#xff0c;最重要的也是最有效的方法其实还是看sql的执行计划&#xff0c;而对于mysql来说&a…

国密SM2 非对称加解密前后端工具

1.依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.21</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcpki…

【银河麒麟操作系统】软raid重建速度限制问题分析

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn 现象描述 遇到软raid重建速度问题&#xff0c;分…

ssm教室信息管理系统+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码看文章最下面 需要定制看文章最下面 目 录 目 录 III 1 绪论 1 1.1 研究背景 1 1.2目的和意义 1 1.3 论文结构安排 2 2 相关技术 3 …

去中心化存储:Web3中的数据安全新标准

随着Web3的兴起&#xff0c;去中心化存储逐渐成为数据安全的新标准。传统的中心化存储方式将数据集中保存在少数服务器上&#xff0c;这种模式尽管在早期互联网中被广泛应用&#xff0c;但随着数据量和数据价值的增加&#xff0c;其潜在的安全风险和隐私问题也逐渐暴露。而去中…

Ubuntu 22 安装 Apache Doris 3.0.3 笔记

Ubuntu 22 安装 Apache Doris 3.0.3 笔记 1. 环境准备 Doris 需要 Java 17 作为运行环境&#xff0c;所以首先需要安装 Java 17。 sudo apt-get install openjdk-17-jdk -y sudo update-alternatives --config java在安装 Java 17 后&#xff0c;可以通过 sudo update-alter…

安卓摄像头的详细使用

安卓摄像头的详细使用 一、引言二、权限设置三、打开摄像头四、摄像头的属性设置&#xff08;一&#xff09;预览尺寸&#xff08;二&#xff09;图片格式&#xff08;三&#xff09;对焦模式 五、摄像头预览六、拍照功能七、视频录制 一、引言 在安卓开发中&#xff0c;摄像头…

服务器的配置复杂,租用时该如何选择参数?

对于互联网企业来说&#xff0c;开发一套可以接入互联网的产品&#xff0c;并利用它来盈利是终极目的。但互联网产品必须有服务器才能运行&#xff0c;对于很多公司来说&#xff0c;托管服务器成本太高&#xff0c;而租用服务器才算得上是最好的选择&#xff0c;但面对配置参数…