GO学习之 同步操作sync包
GO系列
1、GO学习之Hello World
2、GO学习之入门语法
3、GO学习之切片操作
4、GO学习之 Map 操作
5、GO学习之 结构体 操作
6、GO学习之 通道(Channel)
7、GO学习之 多线程(goroutine)
8、GO学习之 函数(Function)
9、GO学习之 接口(Interface)
10、GO学习之 网络通信(Net/Http)
11、GO学习之 微框架(Gin)
12、GO学习之 数据库(mysql)
13、GO学习之 数据库(Redis)
14、GO学习之 搜索引擎(ElasticSearch)
15、GO学习之 消息队列(Kafka)
16、GO学习之 远程过程调用(RPC)
17、GO学习之 goroutine的调度原理
18、GO学习之 通道(nil Channel妙用)
19、GO学习之 同步操作sync包
文章目录
- GO系列
- 前言
- 一、channel 和 sync包
- 1.1 channel 和 sync包性能测试
- 1.2 channel 和 sync包如何选择
- 二、sync包使用注意事项
- 三、sync.Mutex 原理
- 四、小结
前言
按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
同步操作在并发中是必不可少的的,若对一些公用的资源进行操作,为了保证操作的原子和一致性,就需要使用到锁来进行控制。
Go 语言在提供CSP(通信顺序进程)并发模型原语的的同时,还提供了标准库 sync包 针对传统基于共享内存并发模型的同步原语,包括 互斥锁(sync.Mutex)、读写锁(sync.RWMutex)、条件锁(sync.Cond)等。
一、channel 和 sync包
- Go 语言提倡
不要通过共享内存来通信,而是要通过通信来共享内存
,一般的场景中,先使用 CSP 并发模型实现,就是 goroutine + channel 编程。但也有一些特殊的场景,需要 sync包 提供的低级同步原语。 - 在 Go 中,channel 属于高级同步原语,其实现是建立在低级同步原语之上的,所以 channel 自身的性能与低级同步原语相比要稍微逊色一点了。因此,在需要需要高性能的情况下,sync包 提供的低同步原语更为重要。
1.1 channel 和 sync包性能测试
我们来对 channel 和 sync包 的性能做一个对比,示例代码如下(channel_sync_test.go ):
注意!!!
- 基准测试代码文件必须是_test.go结尾,和单元测试一样;
- 基准测试的函数以Benchmark开头;
- 参数为 *testing.B;
- 基准测试函数不能有返回值;
- b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰;
- b.N是基准测试框架提供的,是循环次数,无需关心;
- go test -bench . .\channel_sync_test.go 运行;
package mainimport ("sync""testing"
)var data = 0// 声明互斥锁
var mu sync.Mutex// 声明一个通道
var ch = make(chan struct{}, 1)func syncByMutex() {mu.Lock()data++mu.Unlock()
}func syncByChannel() {ch <- struct{}{}data++<-ch
}// 基准测试函数以 Benchmark 开头
func BenchmarkSectionByMutex(b *testing.B) {for i := 0; i < b.N; i++ {syncByMutex()}
}// 基准测试函数以 Benchmark 开头
func BenchmarkSectionByChannel(b *testing.B) {for i := 0; i < b.N; i++ {syncByChannel()}
}
运行结果:
PS D:\workspaceGo\src\sync> go test -bench . .\channel_sync_test.go
goos: windows
goarch: amd64
cpu: Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz
BenchmarkSectionByMutex-8 79662760 13.15 ns/op
BenchmarkSectionByChannel-8 27814993 40.38 ns/op
PASS
ok command-line-arguments 2.523s
从运行结果中看,BenchmarkSectionByChannel 测试函数是 40.38 ns/op
,BenchmarkSectionByMutex 是 13.15 ns/op
,很明显 sync包 的的性能更佳。
1.2 channel 和 sync包如何选择
- 同步访问 channel 的并发设计的特点是,在 goroutine 间通过 channel 转移数据对象的所有权。只有获得了数据对象的所有权(就是从 channel 中获得该对象)才可以对数据对象进行状态变更。
- 如果设计中没有转移结构体对象所有权,但又要保证结构体内部状态能在多个 goroutine 之间同步,那么你可以使用 sync包 提供的低级同步原语来实现,比如
sync.Mutex
(互斥锁)。
二、sync包使用注意事项
在 sync 包中,有这么些注释:
- Values containing the types defined in this package should not be copied. (不应该包含那些包含了此包中类型的值)
- A Mutex must not be copied after first use. (禁止复制首次使用后的 Mutex)
还有其他 sync包 中也有诸如此类注释,那是为什么呢?我们来进行一个小 demo:
package mainimport ("log""sync""time"
)// 声明一个结构体 data
type data struct {n intsync.Mutex
}func main() {// 声明一个结构体对象 dd := data{n: 100}// 启动一个线程进行加锁操作go func(d data) {for {log.Println("go 2 try to lock...")d.Lock()log.Println("go 2 locked ok...")time.Sleep(3 * time.Second)d.Unlock()log.Println("go 2 unlock ok...")}}(d)d.Lock()log.Println("go main lock ok...")// 在 Mutex 首次使用后复制值go func(d data) {log.Println("go 1 try lock...")d.Lock()log.Println("go 1 locked ok...")time.Sleep(3 * time.Second)d.Unlock()log.Println("go 1 unlock ok...")}(d)time.Sleep(1000 * time.Second)d.Unlock()log.Println("go main unlock ok...")
}
运行结果:
PS D:\workspaceGo\src\sync> go run .\sync.go
2023/11/04 16:57:24 go main lock ok...
2023/11/04 16:57:24 go 2 try to lock...
2023/11/04 16:57:24 go 2 locked ok...
2023/11/04 16:57:24 go 1 try lock...
2023/11/04 16:57:27 go 2 unlock ok...
2023/11/04 16:57:27 go 2 try to lock...
2023/11/04 16:57:27 go 2 locked ok...
2023/11/04 16:57:30 go 2 unlock ok...
2023/11/04 16:57:30 go 2 try to lock...
2023/11/04 16:57:30 go 2 locked ok...
...
在示例中创建了两个 goroutine :go 1 和 go 2,从运行结果中看到 go 1 阻塞在了加锁操作上了,则 go 2 则是按照预期正常运行。go 1 和 go 2 的区别就在于 go 2 是在互斥锁首次使用之前创建的,而 go 1 则是在互斥锁加锁操作并且在锁定状态之后创建的,并且程序在创建 go 1的时候复制了 data 的实例并且使用了这个副本。
三、sync.Mutex 原理
我们可以在 $GOROOT/src/sync/mutex.go 源码中看到如下声明语句:
type Mutex struct {state int32sema uint32
}
其实 sync.Mutex 的实现很简单,定义了两个字段 state 和 sema。
- state:表示当前互斥锁的状态
- sema:用户控制状态的信号量
对Mutex实例的复制即是对两个整型字段的复制。在初始状态下,Mutex 示例处于 Unlocked 状态(state:0,sema:0),上述案例中,go 2 在复制了初始状态的 Mutex 实例,副本的 state 和 sema 均为 0,则与 go 2新定义的 Mutex 无异,则go 2可以继续正常运行。
后续主程序调用了 Lock 方法,Mutex 实例变为 Locked 状态,而此后 go 1 创建是恰恰复制了处于 Locked 状态的实例,那副本实例也是 Locked 状态的,所以 go 1 进去了阻塞状态(也是死锁状态,因为没有任何机会调用 Unlock 了)。
四、小结
通过本文案例可以直观的看到,sync包中的实例在首次实例化后被复制的副本一旦被使用了将导致不可预期的结果。所以在使用 sync包 的时候,推荐通过 闭包 或者 传递类型实例 的地址或指针的方式进行,这是使用 sync包 需要注意的地方。
现阶段还是对 Go 语言的学习阶段,想必有一些地方考虑的不全面,本文示例全部是亲自手敲代码并且执行通过。
如有问题,还请指教。
评论去告诉我哦!!!一起学习一起进步!!!
相关文章:

GO学习之 同步操作sync包
GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、GO学习之 网络通信(Net/Htt…...

NUUO网络摄像头(NVR)RCE漏洞复现
简介 NUUO Network Video Recorder(NVR)是中国台湾NUUO公司的一款网络视频记录器。 NUUO NVR视频存储管理设备的__debugging_center_utils___.php文件存在未授权远程命令执行漏洞,攻击者可在没有任何权限的情况下通过log参数执行任意命令。…...

一款快速获取目标网站关键信息的工具
1.摘要 今天要介绍的这款工具是一个快速收集网站信息的开源脚本, 采用Python语言编写, 该工具可以快速收集网站的页面标题、网站上次更新日期、DNS信息、子域、防火墙名称、网站使用的技术栈、证书等信息, 默认支持对验证码和JavaScript内容执行绕过操作。 2.工具安装使用 使…...

将GC编程语言引入WebAssembly的新方法
本文讨论了一种名为 WasmGC 的新方法,用于将垃圾收集编程语言有效地引入 WebAssembly。 WasmGC 定义了新的 GC 类型,例如结构和数组,与之前编译为线性内存的方法 (WasmMVP) 相比,它们可以实现更好的优化: 在编译时和…...

微信小程序UI自动化测试实践:Minium+PageObject
小程序架构上分为渲染层和逻辑层,尽管各平台的运行环境十分相似,但是还是有些许的区别(如下图),比如说JavaScript 语法和 API 支持不一致,WXSS 渲染表现也有不同,所以不论是手工测试,…...

Java零基础入门-输入与输出
哈喽,各位小伙伴们,你们好呀,我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。 我是一名后…...

iOS报错命名空间“std”中的“unary_function”
刚刚将我的 Xcode 升级到 15.0,突然它开始在 RCT_Folly 中出现以下错误 No template named unary_function in namespace std; did you mean __unary_function?我尝试删除缓存数据和派生数据并清理构建。也尝试删除 pod 和 node_modules。但没有任何帮助。 于是我…...

Flink SQL 窗口聚合详解
1.滚动窗⼝(TUMBLE) **滚动窗⼝定义:**滚动窗⼝将每个元素指定给指定窗⼝⼤⼩的窗⼝,滚动窗⼝具有固定⼤⼩,且不重叠。 例如,指定⼀个⼤⼩为 5 分钟的滚动窗⼝,Flink 将每隔 5 分钟开启⼀个新…...

中间件redis的使用
Java中的中间件配置体现在springboot的yml配置文件中。Springboot框架支持微服务和中间件和restful api远程服务的调用。中间件是Java web系统的中间层的服务系统的调用接口。Springboot的自动装配和约定大于配置机制初始化springcontext的容器空间和注册组件。使用容器管理服务…...

Why delete[] array when deepcopying with “=“?
代码负责释放对象之前已经分配的资源,比如堆上的内存。在执行深拷贝之前,你需要确保对象不再引用之前的资源,以避免内存泄漏。通过删除先前的资源,你可以确保在进行深拷贝之前,已经释放了之前的资源,从而避…...

curl(六)DNS解析、认证、代理
一 DNS解析 ① ip协议 使用ipv4 [-4] 还是ipv6 [-6] ② --resolve 场景: 在不修改系统配置文件 /etc/hosts 的情况下将单个请求临时固定到 ip 地址 1、使用 * 作为通配符,这样请求中调用的所有 Host 都 会转到你指定的 ip curl https://www.wzj.com --resolv…...

(免费领源码)PHP#MySQL高校学生信息管理系统28099-计算机毕业设计项目选题推荐
摘 要 随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联网系统,并对其进行维护和管理。在现实运用中,应用软件的工作规则和开发步骤,采用php技术建设学生信息管理系统设计。…...

[动态规划] (四) LeetCode 91.解码方法
[动态规划] (四) LeetCode 91.解码方法 91. 解码方法 题目解析 (1) 对字母A - Z进行编码1-26 (2)11106可以解码为1-1-10-6或者11-10-6, 但是11-1-06不能解码 (3) 0n不能解码 (4) 字符串非空,返回解码方法的总数 解题思路 状态表示 dp[i]:以i为结…...

Vue Vuex的使用和原理 专门解决共享数据的问题
Vuex专门解决共享数据的问题 多组件共享时使用,如用户ID各组件需要根据ID发送请求获取数据,任意组件可以进行增删改,相当于全局变量 Vuex 工作流程 如果确定值参数可以不经过Actions 直接走 安装Vuex vue2使用 vuex3 vue3使用 vuex4 npm i…...

第九周实验记录
1、安装Nerfstudio 环境配置 首先需要创建环境python3.8,接着需要安装cuda11.7或11.3 这里安装cuda11.7 pip uninstall torch torchvision functorchpip install torch1.13.1 torchvision functorch --extra-index-url https://download.pytorch.org/whl/cu117安…...

STM32WB55开发(6)----FUS更新
STM32WB55开发.6--FUS更新 概述视频教学硬件准备存储器映射FLASH安全区设置SRAM安全区设置通过USB进行下载注意事项 概述 在 STM32WB 微控制器中,FUS(Firmware Upgrade Services)是用于固件升级的一种服务。这项服务可以让你更新设备上的无…...

centos关闭Java进程的脚本
centos关闭Java进程的脚本,有时候服务就是个jar包,关闭程序又要找到进程ID,在kill掉,麻烦,这里就写了个脚本 小白教程,一看就会,一做就成。 1.脚本如下 #!/bin/bash ps -ef | grep java | gre…...

深度学习网络模型 MobileNet系列MobileNet V1、MobileNet V2、MobileNet V3网络详解以及pytorch代码复现
深度学习网络模型 MobileNet系列MobileNet V1、MobileNet V2、MobileNet V3网络详解以及pytorch代码复现 1、DW卷积与普通卷积计算量对比DW与PW计算量普通卷积计算量计算量对比 2、MobileNet V1MobileNet V1网络结构MobileNet V1网络结构代码 3、MobileNet V2倒残差结构模块倒残…...

Spring 中 BeanFactory 和 FactoryBean 有何区别?
这也是 Spring 面试时一道经典的面试问题,今天我们来聊一聊这个话题。 其实从名字上就能看出来个一二,BeanFactory 是 Factory 而 FactoryBean 是一个 Bean,我们先来看下总结: BeanFactory 是 Spring 框架的核心接口之一…...

黑马程序员项目-黑马点评
黑马点评1 短信登录 基于Session实现登录流程 发送验证码: 用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机号 如果手机号合法,后台此时生成对应的验证码,同时将验证码进行…...

ubuntu 20.04 + Anaconda + cuda-11.8 + opencv-4.8.0(cuda)
环境:一键编译opencv-4.8.0(cuda),前提是已经安装好了cuda和cudnn Anaconda安装 参考: https://blog.csdn.net/weixin_46947765/article/details/130980957 opencv4.8.0编译安装 一键编译shell脚本 VERSION4.8.0test -e ${VERSION}.zip || wget http…...

Linux 目录
目录 1. Linux 目录1.1. 目录 /usr/bin 和 /usr/local/bin 区别 1. Linux 目录 1.1. 目录 /usr/bin 和 /usr/local/bin 区别 /usr/bin 下面的都是系统预装的可执行程序, 系统升级有可能会被覆盖。/usr/local/bin 目录是给用户放置自己的可执行程序。...

Linux shell编程学习笔记21:用select in循环语句打造菜单
一、select in循环语句的功能 Linux shell脚本编程提供了select in语句,这是 Shell 独有的一种循环语句,非常适合终端(Terminal)这样的交互场景,它可以根据用户的设置显示出带编号的菜单,用户通过输入不同…...

线性回归与线性拟合的原理、推导与算法实现
关于回归和拟合,从它们的求解过程以及结果来看,两者似乎没有太大差别,事实也的确如此。从本质上说,回归属于数理统计问题,研究解释变量与响应变量之间的关系以及相关性等问题。而拟合是把平面的一系列点,用…...

【C++】set和multiset
文章目录 关联式容器键值对一、set介绍二、set的使用multiset 关联式容器 STL中的部分容器,比如:vector、list、deque、forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元…...

二十、泛型(1)
本章概要 基本概念 与 C 的比较 简单泛型 一个元组类库一个堆栈类RandomList 基本概念 普通的类和方法只能使用特定的类型:基本数据类型或类类型。如果编写的代码需要应用于多种类型,这种严苛的限制对代码的束缚就会很大。 多态是一种面向对象思想的泛…...

【Unity数据交互】游戏中常用到的Json序列化
ˊˊ 👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏࿱…...

TCP的滑动窗口和拥塞控制
目录 滑动窗口 1.发送窗口和接收窗口 2.滑动窗口的分类 停止等待协议:发送窗口大小 1, 接收窗口大小 1 后退N帧协议(GBN):发送窗口大小 > 1,接收窗口大小 1 选择重传协议(SR…...

零信任网络:一种全新的网络安全架构
随着网络技术的不断发展,网络安全问题日益凸显。传统的网络安全策略往往基于信任和验证,但这种信任策略存在一定的局限性。为了解决这一问题,零信任网络作为一种全新的网络安全架构,逐渐受到人们的关注。本文将对零信任网络的概念…...

基于单片机的智能拐杖软件设计
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、整体设计方案2.1本设计设计原理2.1.1单片机基本介绍 二、本设计方案选择三、软件设计AD原理图:原理图…...