欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言原子操作及互斥鎖的區(qū)別

 更新時間:2021年12月10日 15:57:18   作者:小杰的快樂時光  
原子操作就是不可中斷的操作,本文主要介紹了Go語言原子操作及互斥鎖的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

原子操作就是不可中斷的操作,外界是看不到原子操作的中間狀態(tài),要么看到原子操作已經(jīng)完成,要么看到原子操作已經(jīng)結(jié)束。在某個值的原子操作執(zhí)行的過程中,CPU絕對不會再去執(zhí)行其他針對該值的操作,那么其他操作也是原子操作。

Go語言中提供的原子操作都是非侵入式的,在標(biāo)準(zhǔn)庫代碼包sync/atomic中提供了相關(guān)的原子函數(shù)。

增或減

用于增或減的原子操作的函數(shù)名稱都是以"Add"開頭的,后面跟具體的類型名,比如下面這個示例就是int64類型的原子減操作

func main() {
   var  counter int64 =  23
   atomic.AddInt64(&counter,-3)
   fmt.Println(counter)
}
---output---
20

原子函數(shù)的第一個參數(shù)都是指向變量類型的指針,是因為原子操作需要知道該變量在內(nèi)存中的存放位置,然后加以特殊的CPU指令,也就是說對于不能取得內(nèi)存存放地址的變量是無法進(jìn)行原子操作的。第二個參數(shù)的類型會自動轉(zhuǎn)換為與第一個參數(shù)相同的類型。此外,原子操作會自動將操作后的值賦值給變量,無需我們自己手動賦值了。

對于 atomic.AddUint32() 和 atomic.AddUint64() 的第二個參數(shù)為 uint32 與 uint64,因此無法直接傳遞一個負(fù)的數(shù)值進(jìn)行減法操作,Go語言提供了另一種方法來迂回實現(xiàn):使用二進(jìn)制補碼的特性

注意:unsafe.Pointer 類型的值無法被加減。

比較并交換(Compare And Swap)

簡稱CAS,在標(biāo)準(zhǔn)庫代碼包sync/atomic中以”Compare And Swap“為前綴的若干函數(shù)就是CAS操作函數(shù),比如下面這個

func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

第一個參數(shù)的值是這個變量的指針,第二個參數(shù)是這個變量的舊值,第三個參數(shù)指的是這個變量的新值。

運行過程:調(diào)用CompareAndSwapInt32 后,會先判斷這個指針上的值是否跟舊值相等,若相等,就用新值覆蓋掉這個值,若相等,那么后面的操作就會被忽略掉。返回一個 swapped 布爾值,表示是否已經(jīng)進(jìn)行了值替換操作。

與鎖有不同之處:鎖總是假設(shè)會有并發(fā)操作修改被操作的值,而CAS總是假設(shè)值沒有被修改,因此CAS比起鎖要更低的性能損耗,鎖被稱為悲觀鎖,而CAS被稱為樂觀鎖。

CAS的使用示例

var value int32
func AddValue(delta int32)  {
   for {
      v:= value
      if atomic.CompareAndSwapInt32(&value,v,(v+delta)) {
         break
      }
   }
}

由示例可以看出,我們需要多次使用for循環(huán)來判斷該值是否已被更改,為了保證CAS操作成功,僅在 CompareAndSwapInt32 返回為 true時才退出循環(huán),這跟自旋鎖的自旋行為相似。

載入與存儲

對一個值進(jìn)行讀或?qū)憰r,并不代表這個值是最新的值,也有可能是在在讀或?qū)懙倪^程中進(jìn)行了并發(fā)的寫操作導(dǎo)致原值改變。為了解決這問題,Go語言的標(biāo)準(zhǔn)庫代碼包sync/atomic提供了原子的讀?。↙oad為前綴的函數(shù))或?qū)懭耄⊿tore為前綴的函數(shù))某個值

將上面的示例改為原子讀取

var value int32
func AddValue(delta int32)  {
   for {
      v:= atomic.LoadInt32(&value)
      if atomic.CompareAndSwapInt32(&value,v,(v+delta)) {
         break
      }
   }
}

原子寫入總會成功,因為它不需要關(guān)心原值是什么,而CAS中必須關(guān)注舊值,因此原子寫入并不能代替CAS,原子寫入包含兩個參數(shù),以下面的StroeInt32為例:

//第一個參數(shù)是被操作值的指針,第二個是被操作值的新值
func StoreInt32(addr *int32, val int32) 

交換

這類操作都以”Swap“開頭的函數(shù),稱為”原子交換操作“,功能與之前說的CAS操作與原子寫入操作有相似之處。

func SwapInt32(addr *int32, new int32) (old int32)

以 SwapInt32 為例,第一個參數(shù)是int32類型的指針,第二個是新值。原子交換操作不需要關(guān)心原值,而是直接設(shè)置新值,但是會返回被操作值的舊值。

原子值

Go語言的標(biāo)準(zhǔn)庫代碼包sync/atomic中有一個叫做Value的原子值,它是一個結(jié)構(gòu)體類型,用于存儲需要原子讀寫的值,結(jié)構(gòu)體如下

// Value提供原子加載并存儲一致類型的值。
// Value的零值從Load返回nil。
//調(diào)用Store后,不得復(fù)制值。
//首次使用后不得復(fù)制值。
type Value struct {
   v interface{}
}

可以看出結(jié)構(gòu)體內(nèi)是一個 v interface{},也就是說 該Value原子值可以保存任何類型的需要原子讀寫的值。

使用方式如下:

var Atomicvalue  atomic.Value

該類型有兩個公開的指針方法

//原子的讀取原子值實例中存儲的值,返回一個 interface{} 類型的值,且不接受任何參數(shù)。
//若未曾通過store方法存儲值之前,會返回nil
func (v *Value) Load() (x interface{})

//原子的在原子實例中存儲一個值,接收一個 interface{} 類型(不能為nil)的參數(shù),且不會返回任何值
func (v *Value) Store(x interface{})

一旦原子值實例存儲了某個類型的值,那么之后Store存儲的值就必須是與該類型一致,否則就會引發(fā)panic。

嚴(yán)格來講,atomic.Value類型的變量一旦被聲明,就不應(yīng)該被復(fù)制到其他地方。比如:作為源值賦值給其他變量,作為參數(shù)傳遞給函數(shù),作為結(jié)果值從函數(shù)返回,作為元素值通過通道傳遞,這些都會造成值的復(fù)制。

但是atomic.Value類型的指針類型變量就不會存在這個問題,原因是對結(jié)構(gòu)體的復(fù)制不但會生成該值的副本,還會生成其中字段的副本,這樣那么并發(fā)引發(fā)的值變化都與原值沒關(guān)系了。

看下面這個小示例

func main() {
   var Atomicvalue  atomic.Value
   Atomicvalue.Store([]int{1,2,3,4,5})
   anotherStore(Atomicvalue)
   fmt.Println("main: ",Atomicvalue)
}

func anotherStore(Atomicvalue atomic.Value)  {
   Atomicvalue.Store([]int{6,7,8,9,10})
   fmt.Println("anotherStore: ",Atomicvalue)
}
---output---
anotherStore:  {[6 7 8 9 10]}
main:  {[1 2 3 4 5]}

原子操作與互斥鎖的區(qū)別

互斥鎖是一種數(shù)據(jù)結(jié)構(gòu),使你可以執(zhí)行一系列互斥操作。而原子操作是互斥的單個操作,這意味著沒有其他線程可以打斷它。那么就Go語言里atomic包里的原子操作和sync包提供的同步鎖有什么不同呢?

首先atomic操作的優(yōu)勢是更輕量,比如CAS可以在不形成臨界區(qū)和創(chuàng)建互斥量的情況下完成并發(fā)安全的值替換操作。這可以大大的減少同步對程序性能的損耗。

原子操作也有劣勢。還是以CAS操作為例,使用CAS操作的做法趨于樂觀,總是假設(shè)被操作值未曾被改變(即與舊值相等),并一旦確認(rèn)這個假設(shè)的真實性就立即進(jìn)行值替換,那么在被操作值被頻繁變更的情況下,CAS操作并不那么容易成功。而使用互斥鎖的做法則趨于悲觀,我們總假設(shè)會有并發(fā)的操作要修改被操作的值,并使用鎖將相關(guān)操作放入臨界區(qū)中加以保護(hù)。

所以總結(jié)下來原子操作與互斥鎖的區(qū)別有:

互斥鎖是一種數(shù)據(jù)結(jié)構(gòu),用來讓一個線程執(zhí)行程序的關(guān)鍵部分,完成互斥的多個操作。
原子操作是針對某個值的單個互斥操作。
可以把互斥鎖理解為悲觀鎖,共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉(zhuǎn)讓給其它線程。
atomic包提供了底層的原子性內(nèi)存原語,這對于同步算法的實現(xiàn)很有用。這些函數(shù)一定要非常小心地使用,使用不當(dāng)反而會增加系統(tǒng)資源的開銷,對于應(yīng)用層來說,最好使用通道或sync包中提供的功能來完成同步操作。

針對atomic包的觀點在Google的郵件組里也有很多討論,其中一個結(jié)論解釋是:

應(yīng)避免使用該包裝?;蛘?,閱讀C ++ 11標(biāo)準(zhǔn)的“原子操作”一章;如果您了解如何在C ++中安全地使用這些操作,那么你才能有安全地使用Go的 sync/atomic包的能力。

到此這篇關(guān)于Go語言原子操作及互斥鎖的區(qū)別 的文章就介紹到這了,更多相關(guān)Go語言原子操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang中Channel實戰(zhàn)技巧與一些說明

    Golang中Channel實戰(zhàn)技巧與一些說明

    channel是Go語言內(nèi)建的first-class類型,也是Go語言與眾不同的特性之一,下面這篇文章主要給大家介紹了關(guān)于Golang中Channel實戰(zhàn)技巧與一些說明的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • Go語言操作mysql數(shù)據(jù)庫簡單例子

    Go語言操作mysql數(shù)據(jù)庫簡單例子

    這篇文章主要介紹了Go語言操作mysql數(shù)據(jù)庫簡單例子,本文包含插入數(shù)據(jù)和查詢代碼實例,需要的朋友可以參考下
    2014-10-10
  • Go語言服務(wù)器開發(fā)之簡易TCP客戶端與服務(wù)端實現(xiàn)方法

    Go語言服務(wù)器開發(fā)之簡易TCP客戶端與服務(wù)端實現(xiàn)方法

    這篇文章主要介紹了Go語言服務(wù)器開發(fā)之簡易TCP客戶端與服務(wù)端實現(xiàn)方法,實例分析了基于Go語言實現(xiàn)的簡易服務(wù)器的TCP客戶端與服務(wù)器端實現(xiàn)技巧,需要的朋友可以參考下
    2015-02-02
  • golang如何使用sarama訪問kafka

    golang如何使用sarama訪問kafka

    這篇文章主要介紹了golang如何使用sarama訪問kafka,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • 使用Golang進(jìn)行比較版本號大小

    使用Golang進(jìn)行比較版本號大小

    在日常開發(fā)中,比較版本號大小的情況是經(jīng)常遇到的,這篇文章主要為大家詳細(xì)介紹了如何使用Golang進(jìn)行比較版本號大小,需要的小伙伴可以參考下
    2024-01-01
  • 關(guān)于go語言編碼需要放到src 文件夾下的問題

    關(guān)于go語言編碼需要放到src 文件夾下的問題

    這篇文章主要介紹了go語言編碼需要放到src 文件夾下的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • Golang常用包使用介紹

    Golang常用包使用介紹

    標(biāo)準(zhǔn)的Go語言代碼庫中包含了大量的包,并且在安裝Go的時候多數(shù)會自動安裝到系統(tǒng)中。我們可以在$GOROOT/src/pkg目錄中查看這些包。下面簡單介紹一些我們開發(fā)中常用的包
    2022-09-09
  • golang 的string與[]byte轉(zhuǎn)換方式

    golang 的string與[]byte轉(zhuǎn)換方式

    這篇文章主要介紹了golang 的string與[]byte轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 重學(xué)Go語言之基礎(chǔ)數(shù)據(jù)類型詳解

    重學(xué)Go語言之基礎(chǔ)數(shù)據(jù)類型詳解

    Go語言有非常強大的數(shù)據(jù)類型系統(tǒng),其支持的數(shù)據(jù)類型大體上可分為四類:基礎(chǔ)數(shù)據(jù)類型、引用數(shù)據(jù)類型、接口類型、復(fù)合類型。本文就來講講它們各自的用法吧
    2023-02-02
  • golang的HTTP基本認(rèn)證機制實例詳解

    golang的HTTP基本認(rèn)證機制實例詳解

    這篇文章主要介紹了golang的HTTP基本認(rèn)證機制,結(jié)合實例形式較為詳細(xì)的分析了HTTP請求響應(yīng)的過程及認(rèn)證機制實現(xiàn)技巧,需要的朋友可以參考下
    2016-07-07

最新評論