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

Go語(yǔ)言原子操作atomic的使用

 更新時(shí)間:2024年10月21日 10:17:25   作者:CodeJR  
本文介紹了Go語(yǔ)言原子操作的使用方法,原子操作是一種無(wú)鎖的技術(shù),可通過(guò)CPU指令實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

概述

在日常開(kāi)發(fā)中,不可避免的會(huì)碰到并發(fā)場(chǎng)景,在Go語(yǔ)言中處理同步的方法通常是使用鎖,但如果是對(duì)單一的一個(gè)整數(shù)操作,這個(gè)時(shí)候使用鎖可能會(huì)造成更大的性能開(kāi)銷,而且代碼也失去了美觀與優(yōu)雅。

這個(gè)時(shí)候我們可以使用Go語(yǔ)言自帶的原子操作,原子操作在Go語(yǔ)言的sync/atomic標(biāo)準(zhǔn)庫(kù)里面,原子操作是比其他同步技術(shù)更基礎(chǔ)的一種技術(shù),而且原子操作是無(wú)鎖的,通常是直接通過(guò)CPU指令實(shí)現(xiàn)。如果去看其他同步技術(shù)的源碼可以看到很多技術(shù)都是依賴于原子操作的。

同步問(wèn)題

在正式介紹原子操作之前先看一段代碼,該代碼中創(chuàng)建了100000個(gè)協(xié)程,對(duì)一個(gè)公共變量x進(jìn)行累加操作,總共有3個(gè)版本的代碼,第一個(gè)版本是普通版,第二個(gè)版本是加鎖版本,第三個(gè)版本是原子操作版本。

var (
	x    int64
	lock sync.Mutex
	wg   sync.WaitGroup
)

// 普通版
func add() {
	x++
	wg.Done()
}

// 互斥鎖版
func mutexAdd() {
	lock.Lock()
	x++
	lock.Unlock()
	wg.Done()
}

// atomic版
func atomicAdd() {
	atomic.AddInt64(&x, 1)
	wg.Done()
}

func main() {
	start := time.Now()
	for i := 0; i < 100000; i++ {
		wg.Add(1)
		//go add() // 普通版add函數(shù),非并發(fā)安全
		//go mutexAdd() // 加鎖版add函數(shù),并發(fā)安全,但是加鎖性能開(kāi)銷大
		go atomicAdd() // 原子操作版add函數(shù),并發(fā)安全,性能優(yōu)于加鎖版
	}
	wg.Wait()
	end := time.Now()
	fmt.Println("計(jì)算結(jié)果:", x)
	fmt.Println("消耗時(shí)間:", end.Sub(start))
}

依次運(yùn)行三個(gè)版本,得出結(jié)果如下:

# 普通版本
計(jì)算結(jié)果: 96725
消耗時(shí)間: 26.4237ms

# 加鎖版本
計(jì)算結(jié)果: 100000
消耗時(shí)間: 31.2588ms

# 原子操作版本
計(jì)算結(jié)果: 100000
消耗時(shí)間: 27.3615ms

從上面的結(jié)果可以看出,普通版本的直接結(jié)算結(jié)果就是錯(cuò)誤的,這個(gè)因?yàn)槠胀ò姹镜牟皇遣l(fā)安全的,所以會(huì)導(dǎo)致計(jì)算錯(cuò)誤。加鎖版本和原子操作版本都是計(jì)算正確,但是原子操作版本所消耗時(shí)間要比加鎖版本更低(如果數(shù)字更大相差時(shí)間可能會(huì)更多,可以自行嘗試)。

atomic

所有的原子操作都在atomic包下面,對(duì)于int32,int64,uint32,uint64,uintptr和Pointer類型,都有其對(duì)應(yīng)的原子操作。

func SwapInt32(addr *int32, new int32) (old int32)
func SwapInt64(addr *int64, new int64) (old int64)
func SwapUint32(addr *uint32, new uint32) (old uint32)
func SwapUint64(addr *uint64, new uint64) (old uint64)
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)

func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

func AddInt32(addr *int32, delta int32) (new int32)
func AddUint32(addr *uint32, delta uint32) (new uint32)
func AddInt64(addr *int64, delta int64) (new int64)
func AddUint64(addr *uint64, delta uint64) (new uint64)
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

func LoadInt32(addr *int32) (val int32)
func LoadInt64(addr *int64) (val int64)
func LoadUint32(addr *uint32) (val uint32)
func LoadUint64(addr *uint64) (val uint64)
func LoadUintptr(addr *uintptr) (val uintptr)
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

func StoreInt32(addr *int32, val int32)
func StoreInt64(addr *int64, val int64)
func StoreUint32(addr *uint32, val uint32)
func StoreUint64(addr *uint64, val uint64)
func StoreUintptr(addr *uintptr, val uintptr)
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

以上是atomic包中的所有方法,主要分為5種類型,下面根據(jù)不同類型逐一講解。

Load和Store

Load和Store方法主要用來(lái)在并發(fā)環(huán)境下實(shí)現(xiàn)對(duì)數(shù)字的設(shè)置和讀取,Store表示給變量設(shè)置一個(gè)值,Load表示讀取變量的值。

var value int64

func main() {
	atomic.StoreInt64(&value, 1)
	val := atomic.LoadInt64(&value)
	fmt.Println("value: ", val)
}

Add

Add方法更簡(jiǎn)單,就是給一個(gè)變量加上一個(gè)值,使用Add方法加是并發(fā)安全的,不會(huì)出現(xiàn)上面示例中普通版本的add函數(shù)一樣出現(xiàn)計(jì)算錯(cuò)誤的問(wèn)題。如果變量是有符號(hào)整數(shù)類型,需要實(shí)現(xiàn)對(duì)變量的減法,只需要調(diào)用Add方法的時(shí)候第二個(gè)參數(shù)傳入負(fù)數(shù)即可。

Swap和CompareAndSwap

Swap是交換的意思,使用Swap方法可以修改變量的值,同時(shí)會(huì)將變量的舊值返回。

CompareAndSwap是比較并交換的意思,作用與Swap類似,也是修改變量的值,但是在調(diào)用CompareAndSwap的時(shí)候需要傳入需要設(shè)置的新值和期望的舊值,如果當(dāng)前變量的值和期望的舊值一樣,才會(huì)將變量修改會(huì)新值,同時(shí)返回是否修改成功。

var value int64 = 1

func main() {
	old := atomic.SwapInt64(&value, 2)
	fmt.Printf("舊值:%d, value:%d\n", old, value)
	swapped := atomic.CompareAndSwapInt64(&value, 1, 3)
	fmt.Printf("修改結(jié)果:%t, value: %d\n", swapped, value)
	swapped = atomic.CompareAndSwapInt64(&value, 2, 3)
	fmt.Printf("修改結(jié)果:%t, value: %d\n", swapped, value)
}

上面的示例中將value設(shè)置為1,先使用Swap方法將Value修改為2,同時(shí)返回修改前的值。再使用CompareAndSwap想要修改為3,但是因?yàn)閭魅氲钠谕?和value的實(shí)際值2不相等,所以修改失敗,再次調(diào)用期望值為2且value的實(shí)際值為2,則修改成功。運(yùn)行結(jié)果如下:

舊值:1, value:2
修改結(jié)果:false, value: 2
修改結(jié)果:true, value: 3

新版本結(jié)構(gòu)體類型

在1.19版本,Go語(yǔ)言在atomic中新增了Int32,Int64等結(jié)構(gòu)體類型,使用結(jié)構(gòu)體類型進(jìn)行原子操作更簡(jiǎn)單,不需要再想之前一樣每次從atomic中調(diào)用各種類型的方法來(lái)實(shí)現(xiàn)原子操作。而是只需要使用結(jié)構(gòu)體的方法即可直接進(jìn)行原子操作。

var value atomic.Int64

func main() {
	value.Store(1)
	fmt.Println("value: ", value.Load())
	n := value.Add(1)
	fmt.Println("value: ", n)
	old := value.Swap(3)
	fmt.Printf("舊值:%d, value:%d\n", old, value.Load())
	swapped := value.CompareAndSwap(3, 4)
	fmt.Printf("修改結(jié)果:%t, value:%d\n", swapped, value.Load())
}

上面示例中使用的就是最新的寫(xiě)法結(jié)構(gòu)體類型,運(yùn)行結(jié)果如下:

value:  1
value:  2               
舊值:2, value:3       
修改結(jié)果:true, value:4

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

相關(guān)文章

  • Golang 獲取系統(tǒng)信息的實(shí)現(xiàn)

    Golang 獲取系統(tǒng)信息的實(shí)現(xiàn)

    本文主要介紹了Golang 獲取系統(tǒng)信息的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 深入理解Go中defer的機(jī)制

    深入理解Go中defer的機(jī)制

    本文主要介紹了Go中defer的機(jī)制,包括執(zhí)行順序、參數(shù)預(yù)計(jì)算、閉包和與返回值的交互,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-02-02
  • Go語(yǔ)言利用heap實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列

    Go語(yǔ)言利用heap實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中heap的使用以及如何利用heap實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列的相關(guān)資料,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-05-05
  • Go gin框架處理panic的方法詳解

    Go gin框架處理panic的方法詳解

    本文我們介紹下recover在gin框架中的應(yīng)用, 首先,在golang中,如果在子協(xié)程中遇到了panic,那么主協(xié)程也會(huì)被終止,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • 詳解Go語(yǔ)言Sync.Pool為何不加鎖也能夠?qū)崿F(xiàn)線程安全

    詳解Go語(yǔ)言Sync.Pool為何不加鎖也能夠?qū)崿F(xiàn)線程安全

    在這篇文章中,我們將剖析sync.Pool內(nèi)部實(shí)現(xiàn)中,介紹了sync.Pool比較巧妙的內(nèi)部設(shè)計(jì)思路以及其實(shí)現(xiàn)方式。在這個(gè)過(guò)程中,也間接介紹了為何不加鎖也能夠?qū)崿F(xiàn)線程安全,感興趣的可以學(xué)習(xí)一下
    2023-04-04
  • Go+Kafka實(shí)現(xiàn)延遲消息的實(shí)現(xiàn)示例

    Go+Kafka實(shí)現(xiàn)延遲消息的實(shí)現(xiàn)示例

    本文主要介紹了Go+Kafka實(shí)現(xiàn)延遲消息的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Golang中HttpRouter路由的使用詳解

    Golang中HttpRouter路由的使用詳解

    httprouter?是一個(gè)高性能、可擴(kuò)展的HTTP路由,本文將通過(guò)一些簡(jiǎn)單的示例為大家講講httprouter?這個(gè)強(qiáng)大的?HTTP?路由是如何使用的,感興趣的小伙伴可以了解一下
    2023-05-05
  • Go語(yǔ)言學(xué)習(xí)教程之反射的示例詳解

    Go語(yǔ)言學(xué)習(xí)教程之反射的示例詳解

    這篇文章主要通過(guò)記錄對(duì)reflect包的簡(jiǎn)單使用,來(lái)對(duì)反射有一定的了解。文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定幫助,需要的可以參考一下
    2022-09-09
  • Go語(yǔ)言Time包的具體使用

    Go語(yǔ)言Time包的具體使用

    Go語(yǔ)言中有關(guān)于時(shí)間和日期的方法都在time包里面,本文主要介紹了Go語(yǔ)言Time包,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • 詳解Go語(yǔ)言中pprof性能分析與debug調(diào)試技巧

    詳解Go語(yǔ)言中pprof性能分析與debug調(diào)試技巧

    在Go語(yǔ)言開(kāi)發(fā)中,pprof 性能分析與 debug 技巧是高性能 Go 程序開(kāi)發(fā)的重要部分,下面是詳細(xì)講解,適用于性能瓶頸排查、CPU 和內(nèi)存分析、以及服務(wù)調(diào)試
    2025-06-06

最新評(píng)論

天津市| 横山县| 平舆县| 水富县| 玉溪市| 霍城县| 日喀则市| 明星| 六枝特区| 金平| 永定县| 本溪市| 乐业县| 金寨县| 沐川县| 定襄县| 奉节县| 鱼台县| 朝阳县| 双柏县| 泰州市| 东山县| 宜宾县| 嘉善县| 永城市| 蒙山县| 关岭| 芜湖市| 普陀区| 浦北县| 那曲县| 瓮安县| 嘉荫县| 井陉县| 湾仔区| 三河市| 平安县| 晋中市| 剑河县| 通辽市| 东阿县|