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

golang学习笔记——互斥锁sync.Mutex、计数器sync.WaitGroup、读写锁sync.RWMutex

文章目录

  • 互斥锁: sync.Mutex
  • sync.WaitGroup 计数器
    • 例子
    • func (*WaitGroup) Add
    • func (*WaitGroup) Done
    • func (*WaitGroup) Wait
  • 读写互斥锁
  • 参考资料

临界区总是需要通过同步机制进行保护的,否则就会产生竞态条件,导致数据不一致。

互斥锁: sync.Mutex

一个互斥锁可以被用来保护一个临界区,我们可以通过它来保证在同一时刻只有一个 goroutine 处于该临界区之内(同一个时刻只有一个线程能够拿到锁)

先通过一个并发读写的例子演示一下,当多线程同时访问全局变量时,结果会怎样?

package mainimport ("fmt"
)var count intfunc main() {for i := 0; i < 2; i++ {go func() {for i := 1000000; i > 0; i-- {count++}fmt.Println(count)}()}fmt.Scanf("\n") //等待子线程全部结束
}//运行结果
//1003065
//1033207

修改代码,在累加的地方添加互斥锁,就能保证我们每次得到的结果都是想要的值

package mainimport ("fmt""sync"
)var (count intlock  sync.Mutex
)func main() {for i := 0; i < 2; i++ {go func() {for i := 1000000; i > 0; i-- {lock.Lock()count++lock.Unlock()}fmt.Println(count)}()}fmt.Scanf("\n") //等待子线程全部结束
}// 运行结果
//1991307
//2000000

每当有 goroutine 想进入临界区时,都需要先对它进行锁定,并且,每个 goroutine 离开临界区时,都要及时地对它进行解锁,锁定和解锁操作分别通过互斥锁 sync.Mutex 的 Lock 和 Unlock 方法实现。使用互斥锁的时候有以下注意事项:

  • 不要重复锁定互斥锁;
  • 不要忘记解锁互斥锁,必要时使用 defer 语句;
  • 不要对尚未锁定或者已解锁的互斥锁解锁;
  • 不要在多个函数之间直接传递互斥锁。

sync.WaitGroup 计数器

type WaitGroup struct {// contains filtered or unexported fields// 包含已筛选或未导出的字段
}

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

WaitGroup等待goroutines的集合完成。主goroutine调用Add来设置要等待的goroutine的数量。然后,每个goroutine都会运行,并在完成时调用Done。同时,可以使用Wait来阻止,直到所有goroutine都完成。

A WaitGroup must not be copied after first use.
首次使用后不得复制WaitGroup。

In the terminology of the Go memory model, a call to Done “synchronizes before” the return of any Wait call that it unblocks.
在Go内存模型的术语中,对Done的调用在其取消阻止的任何Wait调用返回之前“同步”。

例子

This example fetches several URLs concurrently, using a WaitGroup to block until all the fetches are complete.
此示例同时获取多个URL,使用WaitGroup进行阻止,直到所有获取完成。

package mainimport ("sync"
)type httpPkg struct{}func (httpPkg) Get(url string) {}var http httpPkgfunc main() {var wg sync.WaitGroupvar urls = []string{"http://www.csdn.net/","http://www.youku.com/","http://www.baidu.com/",}for _, url := range urls {// Increment the WaitGroup counter.// 增加WaitGroup计数器。wg.Add(1)// Launch a goroutine to fetch the URL.// 启动goroutine以获取URL。go func(url string) {// Decrement the counter when the goroutine completes.// goroutine完成时递减计数器。defer wg.Done()// Fetch the URL.// 获取URL。http.Get(url)}(url)}// Wait for all HTTP fetches to complete.// 等待所有HTTP获取完成。wg.Wait()
}

func (*WaitGroup) Add

func (wg *WaitGroup) Add(delta int)

Add adds delta, which may be negative, to the WaitGroup counter. If the counter becomes zero, all goroutines blocked on Wait are released. If the counter goes negative, Add panics.

Add向WaitGroup计数器添加可能为负数的delta。如果计数器变为零,则会释放在Wait上阻止的所有goroutines。如果计数器为负数,Add会恐慌。

Note that calls with a positive delta that occur when the counter is zero must happen before a Wait. Calls with a negative delta, or calls with a positive delta that start when the counter is greater than zero, may happen at any time.

请注意,计数器为零时发生的具有正增量的调用必须在等待之前发生。任何时候都可能发生具有负增量的调用,或当计数器大于零时开始的具有正增量的调用。

Typically this means the calls to Add should execute before the statement creating the goroutine or other event to be waited for. If a WaitGroup is reused to wait for several independent sets of events, new Add calls must happen after all previous Wait calls have returned. See the WaitGroup example.

通常,这意味着对Add的调用应该在创建goroutine或其他待等待事件的语句之前执行。如果重用一个WaitGroup来等待多个独立的事件集,则必须在所有以前的wait调用都返回后进行新的Add调用。请参阅WaitGroup示例。

func (*WaitGroup) Done

func (wg *WaitGroup) Done()

Done decrements the WaitGroup counter by one.
Done将WaitGroup计数器递减一。

func (*WaitGroup) Wait

func (wg *WaitGroup) Wait()

Wait blocks until the WaitGroup counter is zero.
等待块,直到WaitGroup计数器为零。

读写互斥锁

互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当我们并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。

读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。

读写锁示例:

package mainimport ("fmt""sync""time"
)var (x      int64wg     sync.WaitGrouplock   sync.Mutexrwlock sync.RWMutex
)func write() {// lock.Lock()   // 加互斥锁rwlock.Lock() // 加写锁x = x + 1time.Sleep(10 * time.Millisecond) // 假设读操作耗时10毫秒rwlock.Unlock()                   // 解写锁// lock.Unlock()                     // 解互斥锁wg.Done()
}func read() {// lock.Lock()                  // 加互斥锁rwlock.RLock()               // 加读锁time.Sleep(time.Millisecond) // 假设读操作耗时1毫秒rwlock.RUnlock()             // 解读锁// lock.Unlock()                // 解互斥锁wg.Done()
}func main() {start := time.Now()for i := 0; i < 10; i++ {wg.Add(1)go write()}for i := 0; i < 1000; i++ {wg.Add(1)go read()}wg.Wait()end := time.Now()fmt.Println(end.Sub(start))
}// 173.3553ms

参考资料

sync包
golang并发之sync包

相关文章:

golang学习笔记——互斥锁sync.Mutex、计数器sync.WaitGroup、读写锁sync.RWMutex

文章目录 互斥锁&#xff1a; sync.Mutexsync.WaitGroup 计数器例子func (*WaitGroup) Addfunc (*WaitGroup) Donefunc (*WaitGroup) Wait 读写互斥锁参考资料 临界区总是需要通过同步机制进行保护的&#xff0c;否则就会产生竞态条件&#xff0c;导致数据不一致。 互斥锁&…...

MFC 加载本地文件设置图标

基于单文件/多文件版 1、在CMainFrame中设置 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {//...........// 从本地文件加载图标HICON hIcon (HICON)::LoadImage(NULL, L"./vip.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);if (hIcon){ // 设置窗口图…...

飞天使-linux操作的一些技巧与知识点6-ansible结合jinja2使用,可规范化进行自动化管控

文章目录 在议playbook虚拟环境中安装ansibleplaybook 结合变量的一些演示普通的vars_files 变量&#xff0c;在同级目录创建目录使用host_vars 定义变量group_vars定义变量根据不同系统操作不同版本传递多个外置变量举例几个不同的示例factswhenloophandlers 与 notifytags 任…...

ROS2 Control分析讲解

ROS2 Control 文章目录 前言简述组成安装 框架Controller ManagerResource ManagerControllersUser Interfaces Hardware ComponentsURDF中的硬件描述机器人运行框架 总结 前言 ros2_control是一个使用&#xff08;ROS 2&#xff09;进行机器人&#xff08;实时&#xff09;控…...

Java TCP(一对一)聊天简易版

客户端 import java.io.*; import java.net.Socket; import java.util.Date; import javax.swing.*;public class MyClient {private JFrame jf;private JButton jBsend;private JTextArea jTAcontent;private JTextField jText;private JLabel JLcontent;private Date data;p…...

2.4 C语言之运算符

2.4 C语言之运算符 一、算术运算符二、关系运算符三、逻辑运算符四、自增自减运算符五、按位运算符六、赋值运算符七、条件表达式八、运算符优先级与求值次序 一、算术运算符 二元算术运算符包括&#xff1a;(加)、-(减)、*(乘)、/(除)、%(取模) 整数除法会截断结果中的小数部…...

做题笔记:SQL Sever 方式做牛客SQL的题目--SQL157

----SQL157 平均播放进度大于60%的视频类别 计算各类视频的平均播放进度&#xff0c;将进度大于60%的类别输出。 注&#xff1a; 播放进度播放时长视频时长*100%&#xff0c;当播放时长大于视频时长时&#xff0c;播放进度均记为100%。 结果保留两位小数&#xff0c;并按播放进…...

微信小程序map视野发生改变时切换定位点

<!--地图--> <view><map id"myMap" style"width: 100%; height: 300px;" latitude"{{latitude}}" longitude"{{longitude}}"scale"{{scale}}" markers"{{markers}}" controls"{{controls}}&q…...

javaweb搭配ajax和json

ajax一般用来前端界面与后端界面交互使用。数据格式一般使用json&#xff0c;优点是便于对象与字符串的转化。 1.不适用json对象封装。 jsp: <script>$.ajax({url: "/LoginServlet",data: {"name":name, "pwd":password},dataType: &qu…...

VS2022 将项目打包,导出为exe运行

我有一个在 VS2022 上开发的程序&#xff0c;基于.net 6框架, 想打包成 .exe程序&#xff0c;以在另一个没有安装VS的机器上运行&#xff0c;另一个机器是Win7系统&#xff0c;上面安装了.net 6框架。 虽然网上很多教程&#xff0c;需要安装Project Installer&#xff0c;配置A…...

【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试【DP】2023C-分班【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录 题目描述与示例题目描述输入描述输出描述示例一输入输出 示例二输入输出 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述与示例 题目描述 幼儿园两个班的小朋友在排队时混在了一起&#xff0c;每位小朋友都知道自己是否与前…...

pr模板哪个网站好?免费Pr模板视频素材下载网站 Prmuban.com

pr模板哪个网站好&#xff1f;哪里可以下载免费的pr模板视频素材&#xff0c;PR模板网&#xff08;Prmuban.com&#xff09;影视后期制作模板视频剪辑素材资源网站。 包含PR模板、PR插件、PR预设、MOGRT、LUT、转场特效、音乐素材、音效素材等&#xff0c;更好的剪辑师必备资源…...

【论文阅读】LoRA: Low-Rank Adaptation of Large Language Models

code&#xff1a;GitHub - microsoft/LoRA: Code for loralib, an implementation of "LoRA: Low-Rank Adaptation of Large Language Models" 做法&#xff1a; 把预训练LLMs里面的参数权重给冻结&#xff1b;向transformer架构中的每一层&#xff0c;注入可训练的…...

MybatisPlus的分页插件

PaginationInnerInterceptor 此插件是核心插件,目前代理了 Executor#query 和 Executor#update 和 StatementHandler#prepare 方法。 在SpringBoot环境中配置方式如下&#xff1a; /*** author giserDev* description 配置分页插件、方言、mapper包扫描等* date 2023-12-13 …...

保障网络安全:了解威胁检测和风险评分的重要性

在当今数字时代&#xff0c;网络安全问题变得愈发突出&#xff0c;而及时发现和迅速应对潜在威胁成为保障组织信息安全的首要任务。令人震惊的是&#xff0c;根据2023年的数据&#xff0c;平均而言&#xff0c;检测到一次网络入侵的时间竟然长达207天。这引起了对安全策略和技术…...

3D摄影棚布光:Set A Light 3D Studio

Set A Light 3D Studio是一款专业的灯光模拟软件&#xff0c;旨在帮助摄影师和电影制片人在电脑上进行虚拟灯光布置和场景模拟&#xff0c;以实现更加精准和高质量的拍摄效果。该软件提供了丰富的灯光和场景模型&#xff0c;支持灵活调整光源位置、强度、颜色和效果等参数&…...

#HarmonyOS:应用的包名配置--应用图标和标签配置--配置链接

配置相关 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/application-component-configuration-stage-0000001478340869-V2 应用的包名配置 应用需要在工程的AppScope目录下的app.json5配置文件中配置bundleName标签&#xff0c;该标签用于标识应用的唯…...

docker小白第三天

docker小白第三天 docker为什么会比虚拟机快 1、docker有着比虚拟机更少的抽象层。不需要Hypervisor实现硬件资源虚拟化&#xff0c;运行在docker容器上的程序直接使用的都是实际物理机的硬件资源&#xff0c;因此在CPU、内存利用率上docker将会在效率上有明显优势。 2、dock…...

FFmpegd的AVBSF

本章主要介绍AVBSF 文章目录 结构体定义对外函数常见的过滤器 从名字我们可以知道这是个码流过滤器&#xff0c;我们最常用的是一个叫做h264_mp4toannexb_bsf的东东 这个过滤器的作用是把h264以MP4格式的NALU转换为annexb&#xff08;0x000001&#xff09; const AVBitStreamF…...

深圳三男子写字楼内吸烟被罚,快用富维AI神器,实时监控防火灾

最近&#xff0c;在深圳&#xff0c;一专项控烟督查组在福田区新华保险大厦发现三名男子在写字楼内楼道违法吸烟&#xff0c;并对其进行了现场处罚。根据《控烟条例》&#xff0c;这类室内区域严禁吸烟&#xff0c;但人们往往忽视这一规定&#xff0c;从而引发潜在的安全风险。…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

背包问题双雄:01 背包与完全背包详解(Java 实现)

一、背包问题概述 背包问题是动态规划领域的经典问题&#xff0c;其核心在于如何在有限容量的背包中选择物品&#xff0c;使得总价值最大化。根据物品选择规则的不同&#xff0c;主要分为两类&#xff1a; 01 背包&#xff1a;每件物品最多选 1 次&#xff08;选或不选&#…...

VSCode 没有添加Windows右键菜单

关键字&#xff1a;VSCode&#xff1b;Windows右键菜单&#xff1b;注册表。 文章目录 前言一、工程环境二、配置流程1.右键文件打开2.右键文件夹打开3.右键空白处打开文件夹 三、测试总结 前言 安装 VSCode 时没有注意&#xff0c;实际使用的时候发现 VSCode 在 Windows 菜单栏…...

[QMT量化交易小白入门]-六十二、ETF轮动中简单的评分算法如何获取历史年化收益32.7%

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。 QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。 文章目录 相关阅读1. 策略概述2. 趋势评分模块3 代码解析4 木头…...

后端下载限速(redis记录实时并发,bucket4j动态限速)

✅ 使用 Redis 记录 所有用户的实时并发下载数✅ 使用 Bucket4j 实现 全局下载速率限制&#xff08;动态&#xff09;✅ 支持 动态调整限速策略✅ 下载接口安全、稳定、可监控 &#x1f9e9; 整体架构概览 模块功能Redis存储全局并发数和带宽令牌桶状态Bucket4j Redis分布式限…...