Golang高并发安全(一)
一、场景
很多时候,我们希望加载配置时只加载一次,因为如连接数据库时较慢且不必加载多次;我们希望关闭通道时只关闭一次,因为关闭多次会报错;我们希望访问一个公共资源时,该资源是完整可靠的。
二、介绍
Golang语言的sync包中的sync.Once可以帮助我们只执行一个场景,其内部只有一个func (o *Once) Do(f func()) { }
方法。该方法不能传递参数,所以有这需求时,可以使用闭包解决。
三、问题的引出
下面模仿我们平常不正确的写法,现在有一个场景:有很多个协程要使用到配置资源,一般先判断里面是否为空,如果为空就要去加载配置资源,然后才能继续下面的任务,假设你是这样写的
package mainimport ("fmt""time"
)var con map[string]string // 全局资源func init_ziyuan() { // 加载配置资源con = map[string]string{"hello": "world"} // 赋值time.Sleep(time.Second) // 模拟耗时操作con = map[string]string{"Areyou": "ok"} // 赋值
}func panduan(i int) { // 模拟多个协程访问公共资源if con == nil { // 如果配置资源没有加载就需要去加载init_ziyuan()fmt.Println(con)} else {fmt.Println(con, i) // 输出此时公共资源con的值}
}func main() {for i := 0; i < 5; i++ { // 模拟多个协程同时访问公共资源go panduan(i)}time.Sleep(time.Second * 3) // 最笨地方法确保主函数不会提前退出
}
/* 结果
map[hello:world] 4
map[hello:world] 2
map[hello:world] 3
map[Areyou:ok]
map[Areyou:ok]
*/
由结果可知,0、1号协程执行的快,就去执行了加载资源配置,然后执行了配置资源中第一个赋值操作,2、3、4号协程执行的慢,此时0、1号协程已经完成赋值操作,因此con全局资源不为空,所以2、3、4号协程就执行了输出操作,而不执行加载资源配置。
这里就引发了问题:
高并发时,多个协程访问的公共资源不一致
加载配置资源的操作发生了两次甚至可能更多次
如果解决以上问题,我们可能想使用互斥锁对加载配置资源时的全局变量加锁,使得配置没有完成,其他协程就不能访问该资源。
但是,在加锁期间,其他协程由于不能访问公共资源而阻塞,这在高并发情况下是不好的,即影响性能,又由于阻塞而不能释放内存资源,导致内存瞬间爆满
四、sync.Once控制并发安全
在上面代码的基础上只增加了两行代码,如下。
package mainimport ("fmt""sync""time"
)var one sync.Once // 定义全局结构体
var con map[string]stringfunc init_ziyuan() {con = map[string]string{"hello": "world"}time.Sleep(time.Second)con = map[string]string{"Areyou": "ok"}
}func panduan(i int) {if con == nil {one.Do(init_ziyuan) // 对资源配置函数调用fmt.Println(con)} else {fmt.Println(con, i)}
}func main() {for i := 0; i < 5; i++ {go panduan(i)}time.Sleep(time.Second * 3)
}
/* 结果
map[hello:world] 2
map[hello:world] 4
map[hello:world] 3
map[hello:world] 0
map[Areyou:ok]
*/
注意:上面的代码在Windows中运行时,结果和错误的代码是一样的,我也不知道为什么。但在Linux环境下执行是对的。可在Golang官网在线执行https://golang.org/
原理(重点)
sync.Once的源码非常简短,也很简单,如下:
// once.go
package syncimport ("sync/atomic"
)type Once struct {done uint32m Mutex
}func (o *Once) Do(f func()) {if atomic.LoadUint32(&o.done) == 0 {o.doSlow(f)}
}func (o *Once) doSlow(f func()) {o.m.Lock()defer o.m.Unlock()if o.done == 0 {defer atomic.StoreUint32(&o.done, 1)f()}
}
done变量是一个没有符号的32位整形,m变量是一个互斥锁。调用Do( init_ziyuan )函数时,首先atomic.LoadUint32( )函数对done进行原子操作,相当于给done加了一个轻量级的锁,并之后返回done这个指针地址指向的值,由于没有初始化,所以它默认为零值,然后执行doSlow( )函数,在doSlow函数中加互斥锁,然后执行f( )函数,也就是我们传进来的init_ziyuan( )函数,执行完后对done进行修改值为1,并设置done的值为1,之后再解锁互斥锁
可以发现done虽然不是一个布尔值,但由于原子操作需要用到int32类型,所以就当做布尔值使用
可以发现互斥锁并不是对全局资源加锁,而是对函数进行加锁,使得函数在短时间内只执行一次
可以发现done变量原子操作是用于保护互斥锁能正常加锁的
Golang高并发安全(一)相关推荐
- golang高并发的理解
转载地址:https://www.cnblogs.com/feixiangmanon/p/10504081.html 前言 GO语言在WEB开发领域中的使用越来越广泛,Hired 发布的<201 ...
- Golang的高并发
Golang的高并发 Golang的调度器有三个核心的元素: 物理处理器 逻辑处理器 goroutine 物理处理器更接近cpu核的概念,主要包括 调度线程来运行. 分配逻辑处理器的基础, 每个物理处 ...
- Golang适合高并发场景的原因分析
典型的两个现实案例: 我们先看两个用Go做消息推送的案例实际处理能力. 360消息推送的数据: 16台机器,标配:24个硬件线程,64GB内存 Linux Kernel 2.6.32 x86_64 ...
- Golang适合高并发场景的原理
典型的两个现实案例: 我们先看两个用Go做消息推送的案例实际处理能力 360消息推送的数据: 16台机器,标配:24个硬件线程,64GB内存 Linux Kernel 2.6.32 x86_64 ...
- Golang语言快速上手到综合实战(Go语言、Beego框架、高并发聊天室、豆瓣电影爬虫) 下载
下载Golang语言快速上手到综合实战(Go语言.Beego框架.高并发聊天室.豆瓣电影爬虫) 下载地址:请加QQ:397245854 Go是Google开发的一种编译型,可并行化,并具有垃圾回收功能 ...
- 当Golang遇到高并发秒杀
遇到go也是工作上的调整,工作上做架构相关的事情,对新发展比较火爆的语言肯定要关注下.就这样步入了GO语言的世界,GO给我带来了全新的体验: 一直做一件事情的人往往会被一件事情所困,开始实践GO语言的 ...
- 高并发C/S的TCP版本golang实现
前面一篇文章写到的实现服务器只能连接一个客户端,没有发挥出go语言的协程特性,所以又可用如下方法实现高并发,多个客户端连接来完成: package mainimport ("fmt" ...
- 坑系列 —— 缓存+哈希=高并发?
2019独角兽企业重金招聘Python工程师标准>>> 今天继续坑系列,高可用已经讲过了,当前互联网时代,怎么少的了高并发呢?高并发和高可用一样, 已经变成各个系统的标配了,如果你的 ...
- 小米开源监控系统OpenFalcon应对高并发7种手段
2019独角兽企业重金招聘Python工程师标准>>> 小米开源监控系统OpenFalcon应对高并发7种手段 原创 2016-04-01 秦晓辉 高可用架构 编者按:本文是秦晓辉在 ...
最新文章
- ubuntu系统在vmware中无法联网问题解决
- Django模版(二)
- 搜索引擎——反向索引原理揭秘及手写ik分词器
- linux下如何批量替换多个文件中的某个字符串?
- 字符串常量与字符串变量
- Cacti Plugin Architecture安装
- 复旦大学邱锡鹏教授带你梳理深度学习知识脉络(直播彩蛋)
- android6.0 framework修改使用两个声卡
- MySQL的索引与事务(面试必考) - 细节狂魔
- Rust Atomic总结笔记
- Access Token是做什么的
- mybatis 一对一、一对多、多对一、多对多
- 在线生成安卓签名证书
- android换肤动画,Android换肤(二) — 插件式换肤
- 寒武纪行歌 - 智能驾驶大算力芯片入局者
- DB2数据库常见问题汇总
- filter- 配置多过滤url
- 2019-6-27-WPF-如何给定两个点画出一条波浪线
- 博通Broadcom SDK源码学习与开发11——Cable Modem DHCP管理
- 给刚出社会的您关于社会的几点建议与看法
热门文章
- python是什么意思中文、好学吗-python好学吗
- (读书笔记) 暗时间 (2016.12.17更)
- EXCELVBA: 中国热力图 HeatMap of China
- 慎读书,精读书,反复读好书并学以致用
- CTF之懵懂时期系列---后台登录
- H3C防火墙web管理
- 核心骨干需要具备的能力
- element中el-dialog组件垂直居中完美解决方案,适配超高dialog
- 十大战略工具(5)—— 通用电气矩阵
- 刺激战场android闪退,《绝地求生刺激战场》老是闪退怎么办 老是闪退解决方法介绍...