自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Golang中的同步工具原子操作詳解

開(kāi)發(fā) 前端
原子操作是指一系列操作要么全部執(zhí)行成功,要么全部執(zhí)行失敗,不會(huì)有中間狀態(tài)。

前面幾篇文章介紹了Golang中互斥鎖、讀寫鎖、條件變量,雖然它們可以很好地協(xié)調(diào)對(duì)共享資源的訪問(wèn),但并不能保證原子操作。

原子操作

原子操作是指一系列操作要么全部執(zhí)行成功,要么全部執(zhí)行失敗,不會(huì)有中間狀態(tài)。

鎖無(wú)法保證原子性是因?yàn)椋?/p>

  • 在鎖保護(hù)的臨界區(qū)代碼執(zhí)行期間,其他協(xié)程無(wú)法訪問(wèn)該代碼段,但是它們可以訪問(wèn)其他資源,可能會(huì)導(dǎo)致原子操作失敗;
  • 鎖雖然能做到只讓一個(gè)goroutine執(zhí)行臨界區(qū)代碼,不被其他goroutine打擾,不過(guò)仍然可能被系統(tǒng)中斷(因?yàn)間oroutine都是統(tǒng)一被runtime調(diào)度的,runtime會(huì)頻繁切換一個(gè)goroutine的運(yùn)行狀態(tài))

可以看出原子操作的粒度更細(xì),它對(duì)單個(gè)變量的訪問(wèn)進(jìn)行了原子化保證,在操作完成之前會(huì)阻塞其他并發(fā)操作。能夠保證原子性執(zhí)行的只有原子操作,原子操作在執(zhí)行過(guò)程中是不允許被中斷的。在計(jì)算機(jī)底層,原子性是由CPU支持的,所以絕對(duì)有效。Golang中的原子操作是基于操作系統(tǒng)和CPU的,具體功能由標(biāo)準(zhǔn)庫(kù)中的sync/atomic包提供。

sync/atomic

sync/atomic包提供的原子操作有Add、Load、Store、Swap和CompareAndSwap,這些函數(shù)支持的數(shù)據(jù)類型有int32、int64、uint32、uint64、uintptr和unsafe包中的Pointer,不過(guò),沒(méi)有提供針對(duì)unsafe.Pointer的Add方法。具體方法如下:

  • AddInt32/AddInt64/AddUint32/AddUint64/AddUintptr: 原子地將指定的值加到一個(gè)地址中的值上。
  • CompareAndSwapInt32/CompareAndSwapInt64/CompareAndSwapUint32/CompareAndSwapUint64/CompareAndSwapUintptr/CompareAndSwapPointer: 原子地比較一個(gè)指定類型地址中的值,如果該值和參數(shù)old匹配,就在那個(gè)地址處存儲(chǔ)參數(shù)new。
  • SwapInt32/SwapInt64/SwapUint32/SwapUint64/SwapUintptr/SwapPointer: 原子地將值存儲(chǔ)在指定地址處,并返回此地址的舊值。
  • LoadInt32/LoadInt64/LoadUint32/LoadUint64/LoadUintptr/LoadPointer: 原子地返回指定地址中的值。
  • StoreInt32/StoreInt64/StoreUint32/StoreUint64/StoreUintptr/StorePointer: 原子地將指定值存儲(chǔ)到指定類型地址中。

此外,sync/atomic包還提供一個(gè)名稱為Value的類型,可以被用來(lái)存儲(chǔ)任意類型的值,結(jié)構(gòu)如下:

type Value struct {
	v any
}

使用方法和示例

使用原子操作可以用于計(jì)算需要在多個(gè)goroutine之間共享的計(jì)數(shù)器。例如,計(jì)算在線用戶數(shù)量、任務(wù)完成情況等等。

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var counter int64
	done := make(chan bool)

	for i := 0; i < 100; i++ {
		go func() {
			atomic.AddInt64(&counter, 1)
			done <- true
		}()
	}

	for i := 0; i < 100; i++ {
		<-done
	}

	fmt.Println(counter)
}

首先聲明了一個(gè)int64類型的計(jì)數(shù)器變量counter,使用AddInt64原子操作對(duì)其進(jìn)行遞增。通過(guò)使用AddInt64,確保了每個(gè)goroutine對(duì)其值的修改操作都能夠安全進(jìn)行。

再看一個(gè)自旋鎖的示例:

package main

import (
	"fmt"
	"sync/atomic"
	"time"
)

func main() {
	sign := make(chan struct{}, 2)
	var num int32
	go func() {
		defer func() {
			sign <- struct{}{}
		}()
		for {
			// 定時(shí)增大num值
			time.Sleep(time.Millisecond * 500)
			newNum := atomic.AddInt32(&num, 2)
			fmt.Printf("num當(dāng)前值為: %d\n", newNum)
			// 滿足條件后退出
			if newNum == 10 {
				break
			}
		}
	}()
	go func() {
		// 定時(shí)檢查num值,等于10則歸零
		defer func() {
			sign <- struct{}{}
		}()
		for {
			if atomic.CompareAndSwapInt32(&num, 10, 0) {
				fmt.Println("已將num歸零")
				break
			}
			time.Sleep(time.Millisecond * 500)
		}
	}()
	<-sign
	<-sign
}
責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2023-06-26 08:28:35

Sync.CondGolang

2023-06-05 09:23:00

Golang同步工具

2023-06-06 08:28:58

Sync.OnceGolang

2021-09-22 12:56:19

編程技能Golang

2023-05-19 07:51:15

ChannelGolang

2023-08-08 14:51:29

2014-01-09 09:45:41

原子飛原子

2010-05-19 10:22:07

2023-07-05 08:38:48

GolangGo語(yǔ)言

2023-08-03 08:48:07

Golang接口

2023-03-30 07:52:03

Golang接口

2023-11-27 15:02:37

BytesGolang

2023-05-29 09:25:38

GolangSelect

2021-06-29 10:07:24

Javalong原子操作

2023-08-31 09:28:12

Golang可導(dǎo)出函數(shù)

2023-10-23 12:35:36

Golang追加操作

2010-02-26 14:29:32

Python 工具

2023-10-31 09:10:39

2023-06-09 08:16:09

GolangStruct Tag

2023-08-02 09:07:27

Golangio 包
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)