Golangpackageatomic库
Go语言在设计上对同步(Synchronization,数据同步和线程同步)提供大量的支持,比如goroutine和channel同步原语,库层面有sync:提供基本的同步原语(比如Mutex、RWMutex、Locker)和工具类(Once、WaitGroup、Cond、Pool、Map)syncatomic:提供变量的原子操作(基于硬件指令compareandswap)
atomic
当我们想要对某个变量并发安全的修改,除了使用官方提供的mutex,还可以使用syncatomic包的原子操作,它能够保证对变量的读取或修改期间不被其他的协程所影响。
atomic包的原子操作是通过CPU指令,也就是在硬件层次去实现的,性能较好,不需要像mutex那样记录很多状态。当然,mutex不止是对变量的并发控制,更多的是对代码块的并发控制,2者侧重点不一样。
atomic这些功能需要非常小心才能正确使用。除了特殊的低级应用程序外,最好使用通道或同步包的工具来完成同步。通过通信共享内存;不要通过共享内存进行通信。
atomic包有几种原子操作,主要是Add、CompareAndSwap、Load、Store、SwapAdd
atomic的Add是针对int和uint进行原子加值的:
当需要添加的值为负数的时候,做减法,正数做加法funcAddInt32(addrint32,deltaint32)(newint32)funcAddUint32(addruint32,deltauint32)(newuint32)funcAddInt64(addrint64,deltaint64)(newint64)funcAddUint64(addruint64,deltauint64)(newuint64)funcAddUintptr(addruintptr,deltauintptr)(newuintptr)CompareAndSwap
比较并交换方法实现了类似乐观锁的功能,只有原来的值和传入的old值一样,才会去修改,
CAS操作,会先比较传入的地址的值是否是old,如果是的话就尝试赋新值,如果不是的话就直接返回false,返回true时表示赋值成功。
funcCompareAndSwapInt32(addrint32,old,newint32)(swappedbool)funcCompareAndSwapInt64(addrint64,old,newint64)(swappedbool)funcCompareAndSwapUint32(addruint32,old,newuint32)(swappedbool)funcCompareAndSwapUint64(addruint64,old,newuint64)(swappedbool)funcCompareAndSwapUintptr(addruintptr,old,newuintptr)(swappedbool)funcCompareAndSwapPointer(addrunsafe。Pointer,old,newunsafe。Pointer)(swappedbool)
需要注意的是,CompareAndSwap有可能产生ABA现象发生。也就是原来的值是A,后面被修改B,再后面修改为A。在这种情况下也符合了CompareAndSwap规则,即使中途有被改动过。Load
从某个地址中取值
Load方法是为了防止在读取过程中,有其他协程发起修改动作,影响了读取结果,常用于配置项的整个读取。funcLoadInt32(addrint32)(valint32)funcLoadInt64(addrint64)(valint64)funcLoadUint32(addruint32)(valuint32)funcLoadUint64(addruint64)(valuint64)funcLoadUintptr(addruintptr)(valuintptr)funcLoadPointer(addrunsafe。Pointer)(valunsafe。Pointer)Store
给某个地址赋值
有原子读取,就有原子修改值,前面提到过的Add只适用于int、uint类型的增减,并没有其他类型的修改,而Sotre方法通过unsafe。Pointer指针原子修改,来达到了对其他类型的修改。
funcStoreInt32(addrint32,valint32)funcStoreInt64(addrint64,valint64)funcStoreUint32(addruint32,valuint32)funcStoreUint64(addruint64,valuint64)funcStoreUintptr(addruintptr,valuintptr)funcStorePointer(addrunsafe。Pointer,valunsafe。Pointer)Swap
交换两个值,并且返回老的值
Swap方法实现了对值的原子交换,不仅int,uint可以交换,指针也可以。funcSwapInt32(addrint32,newint32)(oldint32)funcSwapInt64(addrint64,newint64)(oldint64)funcSwapUint32(addruint32,newuint32)(olduint32)funcSwapUint64(addruint64,newuint64)(olduint64)funcSwapUintptr(addruintptr,newuintptr)(olduintptr)funcSwapPointer(addrunsafe。Pointer,newunsafe。Pointer)(oldunsafe。Pointer)
value类型
最后一类Value用于任意类型的值的Store、Load,我们开始的案例就用到了这个,这是1。4版本之后引入的,签名的方法都只能作用于特定的类型,引入这个方法之后就可以用于任意类型了。
syncatomic标准库包也提供了一个Value类型,以它为基的指针类型Value拥有四个方法(见下,其中后两个是从Go1。17开始才支持的)。Value值用来原子读取和修改任何类型的Go值。func(Value)Load()(xinterface{})func(Value)Store(xinterface{})func(Value)Swap(newinterface{})(oldinterface{})func(Value)CompareAndSwap(old,newinterface{})(swappedbool)CAS
在syncatomic包中的源码除了Value之外其他的函数都是没有直接的源码的,需要去runtimeinternalatomic中找寻,这里为CAS函数为例,其他的都是大同小异boolCas(int32val,int32old,int32new)Atomically:if(valold){valnew;return1;}elsereturn0;TEXTruntimeinternalatomicCas(SB),NOSPLIT,017MOVQptr0(FP),BXMOVLold8(FP),AXMOVLnew12(FP),CXLOCKCMPXCHGLCX,0(BX)SETEQret16(FP)RET
在注释部分写的非常清楚,这个函数主要就是先比较一下当前传入的地址的值是否和old值相等,如果相等,就赋值新值返回true,如果不相等就返回false
我们看这个具体汇编代码就可以发现,使用了LOCK来保证操作的原子性,CMPXCHG指令其实就是CPU实现的CAS操作。示例对比Go语言在设计上对同步(Synchronization,数据同步和线程同步)提供大量的支持,比如goroutine和channel同步原语,库层面有sync:提供基本的同步原语(比如Mutex、RWMutex、Locker)和工具类(Once、WaitGroup、Cond、Pool、Map)syncatomic:提供变量的原子操作(基于硬件指令compareandswap)packagemainimport(fmtsyncsyncatomictime)var(xint64mxsync。Mutexwgsync。WaitGroup)普通函数,并发不安全funcAdd(){xwg。Done()}互斥锁,并发安全,性能低于原子操作funcMxAdd(){mx。Lock()xmx。Unlock()wg。Done()}原子操作,并发安全,性能高于互斥锁,只针对go中的一些基本数据类型使用funcAmAdd(){atomic。AddInt64(x,1)wg。Done()}funcmain(){原子操作atomic包加锁操作涉及到内核态的上下文切换,比较耗时,代价高针对基本数据类型我们还可以使用原子操作来保证并发安全因为原子操作是go语言提供的方法,我们在用户态就可以完成,因此性能比加锁操作更好go语言的原子操作由内置的库,syncatomic完成start:time。Now()fori:0;i10000;i{wg。Add(1)goAdd()普通版Add函数不是并发安全的goMxAdd()加锁版Add函数,是并发安全的,但是加锁性能开销大goAmAdd()原子操作版Add函数,是并发安全的,性能优于加锁版}end:time。Now()wg。Wait()fmt。Println(x)fmt。Println(end。Sub(start))}
Go语言在设计上对同步(Synchronization,数据同步和线程同步)提供大量的支持,比如goroutine和channel同步原语,库层面有sync:提供基本的同步原语(比如Mutex、RWMutex、Locker)和工具类(Once、WaitGroup、Cond、Pool、Map)syncatomic:提供变量的原子操作(基于硬件指令compareandswap)packagemainimport(fmtsyncsyncatomictime)var(xint64mxsync。Mutexwgsync。WaitGroup)普通函数,并发不安全funcAdd(){xwg。Done()}互斥锁,并发安全,性能低于原子操作funcMxAdd(){mx。Lock()xmx。Unlock()wg。Done()}原子操作,并发安全,性能高于互斥锁,只针对go中的一些基本数据类型使用funcAmAdd(){atomic。AddInt64(x,1)wg。Done()}funcmain(){原子操作atomic包加锁操作涉及到内核态的上下文切换,比较耗时,代价高针对基本数据类型我们还可以使用原子操作来保证并发安全因为原子操作是go语言提供的方法,我们在用户态就可以完成,因此性能比加锁操作更好go语言的原子操作由内置的库,syncatomic完成start:time。Now()fori:0;i10000;i{wg。Add(1)goAdd()普通版Add函数不是并发安全的goMxAdd()加锁版Add函数,是并发安全的,但是加锁性能开销大goAmAdd()原子操作版Add函数,是并发安全的,性能优于加锁版}end:time。Now()wg。Wait()fmt。Println(x)fmt。Println(end。Sub(start))}
Go语言在设计上对同步(Synchronization,数据同步和线程同步)提供大量的支持,比如goroutine和channel同步原语,库层面有sync:提供基本的同步原语(比如Mutex、RWMutex、Locker)和工具类(Once、WaitGroup、Cond、Pool、Map)syncatomic:提供变量的原子操作(基于硬件指令compareandswap)packagemainimport(fmtsyncsyncatomictime)var(xint64mxsync。Mutexwgsync。WaitGroup)普通函数,并发不安全funcAdd(){xwg。Done()}互斥锁,并发安全,性能低于原子操作funcMxAdd(){mx。Lock()xmx。Unlock()wg。Done()}原子操作,并发安全,性能高于互斥锁,只针对go中的一些基本数据类型使用funcAmAdd(){atomic。AddInt64(x,1)wg。Done()}funcmain(){原子操作atomic包加锁操作涉及到内核态的上下文切换,比较耗时,代价高针对基本数据类型我们还可以使用原子操作来保证并发安全因为原子操作是go语言提供的方法,我们在用户态就可以完成,因此性能比加锁操作更好go语言的原子操作由内置的库,syncatomic完成start:time。Now()fori:0;i10000;i{wg。Add(1)goAdd()普通版Add函数不是并发安全的goMxAdd()加锁版Add函数,是并发安全的,但是加锁性能开销大goAmAdd()原子操作版Add函数,是并发安全的,性能优于加锁版}end:time。Now()wg。Wait()fmt。Println(x)fmt。Println(end。Sub(start))}
原子操作是比其它同步技术更基础的操作。原子操作是无锁的,常常直接通过CPU指令直接实现。事实上,其它同步技术的实现常常依赖于原子操作。例如上面的的mx。lock
atomic包提供了底层的内存操作,对于同步算法的实现很有用,这些函数必须谨慎的保证正确使用,除了某些特殊的底层应用,使用通道或者sync包的函数类型实现同步更好
atomic很多时候可能都没有使用上,毕竟mutex的拓展性比较好,使用起来也比较友好。但这并不妨碍我们对极致性能的追求,有时候,细节决定了性能!ReferencesGolang:sync。OnceSynchronization(ComputerScience))SIP20ImprovedLazyValsInitializationsyncatomicGoPackagesGolangpackagesync剖析(一):sync。Oncesyncatomic标准库包中提供的原子操作Go并发编程(五)深入理解syncatomicGo语言标准库中atomic。Value的前世今生深入浅出Gosyncatomic源码分析
提示寒露已至,这份防腹泻指南快收好寒露时节,此时气温较白露更低,天凉露重,消化道疾病多发。不同人群应如何预防腹泻?市健促中心为大家带来寒露时节的预防腹泻指南两种情况需谨防寒露时节,消化道疾病多发,尤其以腹泻较为多见
重磅!!构力科技超低能耗近零能耗建筑设计指南发布随着时代的发展,能源问题已经成为世界关注的焦点,节约能源已经成为当今不可回避的难题。不断降低建筑能耗提升建筑能效利用可再生能源,推动建筑迈向超低能耗建筑成为建筑领域的中长期发展目标
外观动感,空间实用,广汽埃安AIONYPLUS值得选择吗?随着国际碳排放标准越来越严格,各大厂商推出新能源车已经成为一种大趋势。新能源车相比传统燃油车有着更加平顺强劲的动力水平以及更低的使用成本,所以很多消费者在选车时都会考虑到新能源车。
回归本源!资管行业从高速增长迈向高质量发展中国基金报记者曹雯璟莫琳闫晶滢见习记者赵心怡党的十八大以来,我国资产管理行业取得了令人瞩目的成就。2018年资管新规又启动了净值化规范化发展新时代银行理财实现跨越式发展,净值化转型
培养大国工匠为奋进的中国凝聚坚实力量近日,中共中央办公厅国务院办公厅印发了关于加强新时代高技能人才队伍建设的意见(以下简称意见),并发出通知,要求各地区各部门结合实际认真贯彻落实。意见从加大高技能人才培养力度完善技能
二手市场两重天Mate50加价,iPhone14跌破官方价刚刚结束的2022年三季度,华为苹果相继发布全新旗舰系列手机。10月10日,转转集团发布2022年三季度手机市场行情报告(以下简称报告),报告显示,苹果iPhone的交易量仍居第一
劳动力市场热度下降缓慢,美联储还有多少耐心?随着美联储大幅加息对经济和企业的影响逐渐释放,美国劳动力市场逐渐远离了上半年的火爆场景。然而就业市场依然趋紧,劳动力参与率复苏乏力或成为推动就业供需平衡的重大障碍。超预期的9月非农
一个爱画画日本人在中国的文化之旅他因为儿时偶然获得的邮票与中国结缘。他在仙台长大,在上海寻找鲁迅足迹。30年来他游历中国多地,用画笔和相机记录了时代的变迁。他是大泉直人,武田(中国)投资有限公司法务部高级专利顾问
以理服人为什么要抓好维护国家安全这一头等大事?视频加载中十年非凡成就,蕴藏深刻启示。如何用中国理论阐释中国实践?新华网联合中央党校(国家行政学院)国家高端智库,推出思客讲堂党校公开课(第三季)以理服人十年的十个为什么。十位党校
国家统计局我国高水平开放成效显著贸易大国地位更加巩固央视网消息国家统计局今天(10月9日)发布,党的十八大以来,我国对外开放水平达到前所未有的高度,对外贸易规模稳定增长,贸易大国地位更加巩固。20132021年,我国累计货物贸易进出
巴媒葡语国家参与一带一路前景看好据巴西里约时报在线网站9月28日报道,根据在澳门举行的国际基础设施投资与建设高峰论坛发布的一带一路国家基础设施发展指数报告(2022),巴西安哥拉和葡萄牙是其中得分最高的葡萄牙语国