Golang sync/atomic包——原子操作
1、概述
1.1 基本概念
原子性:一个或多个操作在CPU的执行过程中不被中断的特性,称为原子性。这些操作对外表现成一个不可分割的整体,他们要么都执行,要么都不执行,外界不会看到他们只执行到一半的状态。
原子操作:进行过程中不能被中断的操作,原子操作由底层硬件支持,而锁则是由操作系统提供的API实现,若实现相同的功能,前者通常会更有效率
Golang 中的原子操作:sync/atomic包
能够进行原子操作的类型:int32, int64, uint32, uint64, uintptr, unsafe.Pointer
五种操作函数:增或减、比较并交换、载入、存储、交换
原子操作比锁更为高效。
1.2 原子操作 vs 锁
- 加锁比较耗时,需要上下文切换。即使是goroutine也需要上下文切换
- 只针对基本类型,可使用原子操作保证线程安全
- 原子操作在用户态完成,性能比互斥锁要高
- 原子操作步骤简单,不需要加锁-操作-解锁
1.3 五种操作
- 增或减 (Add)
- 比较并交换 (CAS, Compare & Swap)
- 载入 (Load)
- 存储 (Store)
- 交换 (Swap)
1.4 最小案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package main import ( "sync" "fmt" ) var count int func add(wg *sync.WaitGroup) { defer wg.Done() count++ } func main() { wg := sync.WaitGroup{} wg.Add(1000) for i := 0; i < 1000; i++ { go add(&wg) } wg.Wait() fmt.Println(count) } |
count
不会等于1000,因为count++
这一步实际是三个操作:
- 从内存读取
count
- CPU更新
count = count + 1
- 写入
count
到内存
因此就会出现多个goroutine读取到相同的数值,然后更新同样的数值到内存,导致最终结果比预期少。
2、sync/atomic包使用
Go语言提供的原子操作都是非入侵式的,由标准库中sync/aotomic
中的众多函数代表
atomic包中支持六种类型
int32
uint32
int64
uint64
uintptr
unsafe.Pointer
对于每一种类型,提供了五类原子操作:
LoadXXX(addr)
: 原子性的获取*addr
的值,等价于:1return *addr
StoreXXX(addr, val)
: 原子性的将val
的值保存到*addr
,等价于:1addr = val
AddXXX(addr, delta)
: 原子性的将delta
的值添加到*addr
并返回新值(unsafe.Pointer
不支持),等价于:12*addr += delta
return *addr
SwapXXX(addr, new) old
: 原子性的将new
的值保存到*addr
并返回旧值,等价于:123old = *addr
*addr = new
return old
CompareAndSwapXXX(addr, old, new) bool
: 原子性的比较*addr
和old
,如果相同则将new
赋值给*addr
并返回true
,等价于:12345if *addr == old {
*addr = new
return true
}
return false
因此第一部分的案例可以修改如下,即可通过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 修改方式1 func add(wg *sync.WaitGroup) { defer wg.Done() atomic.AddInt32(&count, 1) } // 修改方式2 func add(wg *sync.WaitGroup) { defer wg.Done() for { if atomic.CompareAndSwapInt32(&count, count, count+1) { break } } } |
参考:https://juejin.cn/post/6844904053042839560
参考:https://blog.csdn.net/elihe2011/article/details/109157797
分类:
Golang
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2018-01-18 jconsole监控远程 spring boot程序
2018-01-18 Dokcerfile部署webpy,安装imagehash库并运行py脚本获取图片dhash值
2017-01-18 centos6.8安装Discuz!X3.1(PHP论坛)
2015-01-18 POJ1061:青蛙的约会+POJ2115C Looooops+UVA10673Play with Floor and Ceil(扩展欧几里得)