Go原子操作之Atomic包

一、原子操作概念

在一个高并发的go程序执行过程中,同一时刻很少的groutine在运行。程序的并发性能以及运行效率取决于程序的设计以及运行的环境配置。Go任务调度器公平起见,Groutine频繁的会被换上换下来回切换,来达到高并发的效果。所以在一个groutine执行某个操作时很可能被打断,这就是非原子操作不安全的。

原子操作是安全的,再一次执行过程中是不回被打断的。底层是cpu芯片级别的支持,绝对是有效的,即使是多核心的cpu 或者多cpu的操作系统,原子操作的保证也是不可撼动。

二、automic包核心方法

  1. AddInt32/AddInt64:原子地将一个32位或64位整数加上一个增量,并返回新值。

  2. CompareAndSwapInt32/CompareAndSwapInt64:比较并交换一个32位或64位整数的值,如果当前值等于旧值,则将其替换为新值,并返回true;否则返回false。

  3. LoadInt32/LoadInt64:原子地读取一个32位或64位整数的值,并返回该值。

  4. StoreInt32/StoreInt64:原子地将一个32位或64位整数的值存储到指定的内存地址中。

  5. SwapInt32/SwapInt64:原子地交换一个32位或64位整数的值,并返回旧值。

  6. AddUint32/AddUint64:原子地将一个32位或64位无符号整数加上一个增量,并返回新值。

  7. CompareAndSwapUint32/CompareAndSwapUint64:比较并交换一个32位或64位无符号整数的值,如果当前值等于旧值,则将其替换为新值,并返回true;否则返回false。

  8. LoadUint32/LoadUint64:原子地读取一个32位或64位无符号整数的值,并返回该值。

  9. StoreUint32/StoreUint64:原子地将一个32位或64位无符号整数的值存储到指定的内存地址中。

  10. SwapUint32/SwapUint64:原子地交换一个32位或64位无符号整数的值,并返回旧值

三、原子操作的重点思想

原子操作函数需要的是被操作值的指针,而不是这个值本身;被传入函数的参数值都会被复制,像这种基本类型的值一旦被传入函数,就已经与函数外的那个值毫无关系了。

所以,传入值本身没有任何意义。unsafe.Pointer类型虽然是指针类型,但是那些原子操作函数要操作的是这个指针值,而不是它指向的那个值,所以需要的仍然是指向这个指针值的指针。

只要原子操作函数拿到了被操作值的指针,就可以定位到存储该值的内存地址。只有这样,它们才能够通过底层的指令,准确地操作这个内存地址上的数据。

四. 应用实践
2.1 怎样用好sync/atomic.Value?
为了扩大原子操作的适用范围,Go 语言在 1.4 版本发布的时候向sync/atomic包中添加了一个新的类型Value。此类型的值相当于一个容器,可以被用来“原子地”存储和加载任意的值。

atomic.Value类型是开箱即用的,我们声明一个该类型的变量(以下简称原子变量)之后就可以直接使用了。这个类型使用起来很简单,它只有两个指针方法:Store和Load。不过,虽然简单,但还是有一些值得注意的地方的。

首先一点,一旦atomic.Value类型的值(以下简称原子值)被真正使用,它就不应该再被复制了。什么叫做“真正使用”呢?

我们只要用它来存储值了,就相当于开始真正使用了。atomic.Value类型属于结构体类型,而结构体类型属于值类型。

所以,复制该类型的值会产生一个完全分离的新值。这个新值相当于被复制的那个值的一个快照。之后,不论后者存储的值怎样改变,都不会影响到前者,反之亦然。

五、原子操作与互斥锁对比
原子操作实现的功能我们使用互斥锁也能实现,但是原子操作是更加轻量级的。

原子操作会直接通过CPU指令保证当前Goroutine在执行操作时不会被其它线程所抢占。而互斥锁实现的操作,当前执行Goroutine是会被其它Goroutine抢占的,但是其它的Goroutine在未获取锁的情况并不能顺利执行,从而保证了并发的安全性。

所以,原子操作相对于互斥锁,大大的减少了同步Goroutine对程序性能的损耗。

原子操作能够使用的场景很少,是有很大局限性的。但是在能够使用原子操作的情况下,用它来代替互斥锁,对程序性能的提升是非常大的。

六. 总结

其次,原子值的Store方法对其参数值(也就是被存储值)有两个强制的约束。

一个约束是,参数值不能为nil。
另一个约束是,参数值的类型不能与首个被存储值的类型不同。也就是说,一旦一个原子值存储了某个类型的值,那它以后就只能存储这个类型的值了。
基于上面这几个注意事项,我提出了几条使用建议,包括:不要对外暴露原子变量、不要传递原子值及其指针值、尽量不要在原子值中存储引用类型的值,等等。与之相关的一些解决方案我也一并提出了。希望你能够受用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值