原子操做,意思就是執行的過程不能背終端的操做。在針對某個值的原子操做執行過程當中,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 }