最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

增或減

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

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

原子函數(shù)的第一個(gè)參數(shù)都是指向變量類型的指針,是因?yàn)樵硬僮餍枰涝撟兞吭趦?nèi)存中的存放位置,然后加以特殊的CPU指令,也就是說對(duì)于不能取得內(nèi)存存放地址的變量是無法進(jìn)行原子操作的。第二個(gè)參數(shù)的類型會(huì)自動(dòng)轉(zhuǎn)換為與第一個(gè)參數(shù)相同的類型。此外,原子操作會(huì)自動(dòng)將操作后的值賦值給變量,無需我們自己手動(dòng)賦值了。

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

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

比較并交換(Compare And Swap)

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

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

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

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

與鎖有不同之處:鎖總是假設(shè)會(huì)有并發(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時(shí)才退出循環(huán),這跟自旋鎖的自旋行為相似。

載入與存儲(chǔ)

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

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

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

原子寫入總會(huì)成功,因?yàn)樗恍枰P(guān)心原值是什么,而CAS中必須關(guān)注舊值,因此原子寫入并不能代替CAS,原子寫入包含兩個(gè)參數(shù),以下面的StroeInt32為例:

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

交換

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

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

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

原子值

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

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

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

使用方式如下:

var Atomicvalue  atomic.Value

該類型有兩個(gè)公開的指針方法

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

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

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

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

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

看下面這個(gè)小示例

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í)行一系列互斥操作。而原子操作是互斥的單個(gè)操作,這意味著沒有其他線程可以打斷它。那么就Go語言里atomic包里的原子操作和sync包提供的同步鎖有什么不同呢?

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

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

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

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

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

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

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

相關(guān)文章

  • 詳解Go語言中如何創(chuàng)建Cron定時(shí)任務(wù)

    詳解Go語言中如何創(chuàng)建Cron定時(shí)任務(wù)

    Cron是一個(gè)強(qiáng)大的定時(shí)任務(wù)調(diào)度庫,它允許開發(fā)者在Go應(yīng)用中方便地設(shè)置和管理定時(shí)任務(wù),本文將結(jié)合具體案例,詳細(xì)介紹Cron在Go語言中的用法,需要的可以參考下
    2024-10-10
  • go實(shí)現(xiàn)grpc四種數(shù)據(jù)流模式

    go實(shí)現(xiàn)grpc四種數(shù)據(jù)流模式

    這篇文章主要為大家介紹了go實(shí)現(xiàn)grpc四種數(shù)據(jù)流模式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go語言hello world實(shí)例

    Go語言hello world實(shí)例

    這篇文章主要介紹了Go語言hello world實(shí)例,本文先是給出了hello world的代碼實(shí)例,然后對(duì)一些知識(shí)點(diǎn)和技巧做了解釋,需要的朋友可以參考下
    2014-10-10
  • Golang超全面講解并發(fā)

    Golang超全面講解并發(fā)

    goroutine?不是os線程、不是綠色線程(由語言運(yùn)行時(shí)管理的線程),是協(xié)程。協(xié)程是一種非搶占式的簡(jiǎn)單并發(fā)子goroutine(函數(shù)、閉包或方法),也就是說,它們不能被中斷。取而代之的是,協(xié)程有多個(gè)點(diǎn),允許暫停或重新進(jìn)入?—Go語言并發(fā)之道
    2022-06-06
  • Golang結(jié)構(gòu)化日志包log/slog的使用詳解

    Golang結(jié)構(gòu)化日志包log/slog的使用詳解

    官方提供的用于打印日志的包是標(biāo)準(zhǔn)庫中的 log 包,該包雖然被廣泛使用,但是缺點(diǎn)也很多,所以Go 1.21新增的 log/slog 完美解決了以上問題,下面我們就來看看log/slog包的使用吧
    2023-09-09
  • go語言獲取系統(tǒng)盤符的方法

    go語言獲取系統(tǒng)盤符的方法

    這篇文章主要介紹了go語言獲取系統(tǒng)盤符的方法,涉及Go語言調(diào)用winapi獲取系統(tǒng)硬件信息的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • 深入探索Go?1.21中的?maps工具庫

    深入探索Go?1.21中的?maps工具庫

    隨著?Go?1.21.0?版本的發(fā)布,新增了兩個(gè)實(shí)用的泛型工具庫:maps?和?slices,下面小編就帶大家一起學(xué)習(xí)一下?maps?工具庫的相關(guān)知識(shí)吧
    2023-08-08
  • 詳解Golang并發(fā)操作中常見的死鎖情形

    詳解Golang并發(fā)操作中常見的死鎖情形

    在Go的協(xié)程里面死鎖通常就是永久阻塞了,本文主要介紹了Golang并發(fā)操作中常見的死鎖情形,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-09-09
  • Go語言中XML文件的讀寫操作

    Go語言中XML文件的讀寫操作

    本文主要介紹了Go語言中XML文件的讀寫操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Go語言map字典用法實(shí)例分析

    Go語言map字典用法實(shí)例分析

    這篇文章主要介紹了Go語言map字典用法,實(shí)例分析了map字典的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02

最新評(píng)論

林西县| 白朗县| 汶上县| 梓潼县| 会昌县| 邵东县| 酉阳| 博罗县| 阜新| 嘉兴市| 剑阁县| 晴隆县| 芮城县| 嘉鱼县| 康马县| 离岛区| 合肥市| 洞口县| 泗阳县| 娱乐| 壤塘县| 河南省| 樟树市| 漠河县| 景宁| 柘城县| 万安县| 新和县| 临潭县| 邳州市| 介休市| 万源市| 上栗县| 商洛市| 揭西县| 浪卡子县| 安图县| 广元市| 伽师县| 承德县| 太湖县|