Golang atomic元子操作

  • Code, Golang
  • 49 clicked

1. atomic介绍

sync/atomic包提供了原子操作的能力,直接有底层CPU硬件支持,因而一般要比基于操作系统API的锁方式效率高些;这些功能需要非常小心才能正确使用。 除特殊的底层应用程序外,同步更适合使用channel或sync包的功能。 通过消息共享内存; 不要通过共享内存进行通信。

原子操作是在执行中不能被中断的操作,通常由CPU芯片级能力来保证,并由操作系统提供调用,golang基于操作系统的能力,也提供了基于原子操作的支持。

1.1. 原子操作与临界区的区别

原子操作是能保证执行期间连续的,不会被中断

临界区只能保证访问共享数据是按顺序访问的,但不保证访问期间不会被切换context

1.2. golang提供的原子操作

sync/atomic是go语言提供的非侵入式原子操作包。

Go语言提供的原子操作都是非侵入式的。它们由标准库代码包sync/atomic中的众多函数代表。

我们可以通过调用sync/atomic这些函数对几种简单的类型的值进行原子操作。

这些类型包括int32、int64、uint32、uint64、uintptr和unsafe.Pointer类型,共6个。

这些函数提供的原子操作共有5种,即:增或减、比较并交换、载入、存储和交换。

1.3. 侵入式和非侵入式

侵入式和非侵入式,是从调用关系角度来说的。

比如模块A,调用了模块B中部分功能。
那么模块A是将模块B作为自己的一部分,还是将B作为一个独立的部分,然后再去调用。

如果将模块B作为模块A的一部分,就是侵入式;

如果将B作为一个独立的部分,则为非侵入式。侵入式,往往则意味着高耦合。

2. 操作包

2.1. 基础操作API

add、cas、load、store、swap

int32 int64 uint32 uint64 uintptr unsafe.Pointer Value

  • 原子操作函数的第一个参数都是传变量地址的,因为原子函数需要改变变量的值
  • 原子操作函数可以给add传入负数来做减法,计算机内部都是补码加法,没有减法
  • cas是带条件的swap,只有符合条件才swap

2.1.1. 自增和自减的操作API

2.1.2. 对于比较和交换的操作API

2.1.3. 载入操作API

2.1.4. 存储操作API

2.1.5. 交换操作API

2.2. atomic.Value

  • 支持原子性的load/store任意值
  • 一旦开始存一个值那么后续所有值的类型必须和第一个值的类型一致
  • 不支持nil
  • 不能copy,copy后就是另一个Value了
  • 不建议存储引用类型的值
  • 建议是私有变量,不要对外公开,更新需要严格检查条件

3. atomic.Value vs sync.Mutex

  • atomic.Value 简单、性能好,无死锁问题,但限制多
  • sync.Mutex 是通用的锁保护方案
  • 优先选择atomic.Value

4. 示例

赞赏

微信赞赏支付宝赞赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注