原子操做,意思就是执行的过程不能背终端的操做。在针对某个值的原子操做执行过程当中,cpu不会再去执行其余针对这个值得操做。在底层,这会由CPU提供芯片级别的支持,因此绝对有效。即便在拥有多CPU核心,或者多CPU的计算机系统中,原子操做的保证也是不可撼动的。
Go语言提供了院子操做的包atomic。其中有不少函数能够帮助咱们进行原子操做。可是只能对几种简单类型进行原子操做:int3二、int6四、uint3二、uint6四、uintptr和unsafe.Ponter。atomic为这些简单类型童工了5中操做函数:增或减、比较并交换、载入、存储和交换。数组
咱们知道go语言在sync包中提供了锁的包,可是为何咱们还要使用atomic原子操做呢?总结下来有一下几个缘由:安全
一下5中操做例子都是用uint64来写并发
针对以上6种简单类型,atomic包支持院子增/减的操做函数。函数
var i64 uint64 //第一个参数必须是指针 atomic.AddUint64(&i64,5) //在uint类型中可使用^uint64(0)的方式打到减的效果 atomic.AddUint64(&i64, ^uint64(0)) fmt.Println(i64)
var i64 uint64 i64 = 5 // cas接受3个参数,第一个为须要替换值得指针,第二个为旧值,第三个为新值 // 当指针指向的值,跟你传递的旧值相等的状况下 指针指向的值会被替换 ok := atomic.CompareAndSwapUint64(&i64,5, 50) fmt.Println(ok) // 当指针指向的值跟传递的旧值不相等,则返回false ok = atomic.CompareAndSwapUint64(&i64,40, 50) fmt.Println(ok)
var i64 uint64 i64 = 1 //load 函数接收一个指针类型 返回指针指向的值 num := atomic.LoadUint64(&i64) fmt.Println(num)
var i64 uint64 i64 = 1 //store 函数接受一个指针类型和一个值 函数将会把值赋到指针地址中 atomic.StoreUint64(&i64, 5) fmt.Println(i64)
var i64 uint64 i64 = 1 //swap接受一个指针 一个值。函数会把值赋给指针 并返回旧值 old := atomic.SwapUint64(&i64, 5) fmt.Println("old:",old,"new:",i64)
原子值可接受的备操做值得类型不限,这意味着咱们能够把任何类型的值放入原子值。原子值只有2个公开的方法:Load、Store。一个是获取另外一个是存储。
下面来看下简单操做:性能
var countVal atomic.Value //store函数 接受interface 并存储 countVal.Store([]int{1,2,3,4,5}) //load函数 返回 atomic.value中的值 list := countVal.Load().([]int) fmt.Println(list)
下面有一个并发安全的int数组的例子ui
package main import ( "errors" "sync/atomic" ) func main() { } // ConcurrentArray 表明并发安全的整数数组接口。 type ConcurrentArray interface { // Set 用于设置指定索引上的元素值。 Set(index uint32, elem int) (err error) // Get 用于获取指定索引上的元素值。 Get(index uint32) (elem int, err error) // Len 用于获取数组的长度。 Len() uint32 } type MyArray struct { val atomic.Value length uint32 } func (array *MyArray)CheckValue()(err error){ if array.val.Load() == nil{ errors.New("array is empty") } return nil } func (array *MyArray)CheckIndex(index uint32)(error){ if array.length <= index{ errors.New("array out of the range") } return nil } func (m *MyArray)Set(index uint32, elem int)(err error){ if err := m.CheckValue();err != nil{ return err } if err = m.CheckIndex(index);err!=nil{ return err } newArray := make([]int, m.length) copy(newArray ,m.val.Load().([]int)) newArray[index] = elem m.val.Store(newArray) return nil } func (array *MyArray)Get(index uint32) (elem int, err error){ if err := array.CheckValue();err != nil{ return 0,err } if err = array.CheckIndex(index);err!=nil{ return 0,err } num := array.val.Load().([]int)[index] return num, err }