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

詳解go語言中并發(fā)安全和鎖問題

 更新時(shí)間:2021年10月29日 08:56:51   作者:CJ-cooper  
這篇文章主要介紹了go語言中并發(fā)安全和鎖問題,包含互斥鎖解鎖過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

首先可以先看看這篇文章,對鎖有些了解

GO語言并發(fā)編程之互斥鎖、讀寫鎖詳解

Mutex-互斥鎖

Mutex 的實(shí)現(xiàn)主要借助了 CAS 指令 + 自旋 + 信號量

數(shù)據(jù)結(jié)構(gòu):

type Mutex struct {
	state int32
	sema  uint32
}

上述兩個(gè)加起來只占 8 字節(jié)空間的結(jié)構(gòu)體表示了 Go語言中的互斥鎖

狀態(tài):

在默認(rèn)情況下,互斥鎖的所有狀態(tài)位都是 0,int32 中的不同位分別表示了不同的狀態(tài):

  • 1位表示是否被鎖定
  • 1位表示是否有協(xié)程已經(jīng)被喚醒
  • 1位表示是否處于饑餓狀態(tài)
  • 剩下29位表示阻塞的協(xié)程數(shù)

正常模式和饑餓模式

正常模式:所有g(shù)oroutine按照FIFO的順序進(jìn)行鎖獲取,被喚醒的goroutine和新請求鎖的goroutine同時(shí)進(jìn)行鎖獲取,通常新請求鎖的goroutine更容易獲取鎖(持續(xù)占有cpu),被喚醒的goroutine則不容易獲取到鎖

饑餓模式:所有嘗試獲取鎖的goroutine進(jìn)行等待排隊(duì),新請求鎖的goroutine不會進(jìn)行鎖獲取(禁用自旋),而是加入隊(duì)列尾部等待獲取鎖

如果一個(gè) Goroutine 獲得了互斥鎖并且它在隊(duì)列的末尾或者它等待的時(shí)間少于 1ms,那么當(dāng)前的互斥鎖就會切換回正常模式。

與饑餓模式相比,正常模式下的互斥鎖能夠提供更好地性能,饑餓模式的能避免 Goroutine 由于陷入等待無法獲取鎖而造成的高尾延時(shí)。

互斥鎖加鎖過程

  • 如果互斥鎖處于初始狀態(tài),會直接加鎖
  • 如果互斥鎖處于加鎖狀態(tài),并且工作在普通模式下,goroutine會進(jìn)入自旋,等待鎖的釋放

goroutine 進(jìn)入自旋的條件非??量蹋?/p>

  • 互斥鎖只有在普通模式才能進(jìn)入自旋;
  • runtime.sync_runtime_canSpin需要返回 true

運(yùn)行在多 CPU 的機(jī)器上;

當(dāng)前 Goroutine 為了獲取該鎖進(jìn)入自旋的次數(shù)小于四次;

當(dāng)前機(jī)器上至少存在一個(gè)正在運(yùn)行的處理器 P 并且處理的運(yùn)行隊(duì)列為空;

  • 如果當(dāng)前 Goroutine 等待鎖的時(shí)間超過了 1ms,互斥鎖就會切換到饑餓模式;
  • 互斥鎖在正常情況下會通runtime.sync_runtime_SemacquireMutex將嘗試獲取鎖的 Goroutine 切換至休眠狀態(tài),等待鎖的持有者喚醒;
  • 如果當(dāng)前 Goroutine 是互斥鎖上的最后一個(gè)等待的協(xié)程或者等待的時(shí)間小于 1ms,那么它會將互斥鎖切換回正常模式;

互斥鎖解鎖過程

當(dāng)互斥鎖已經(jīng)被解鎖時(shí),再解鎖會拋出異常

當(dāng)互斥鎖處于饑餓模式時(shí),將鎖的所有權(quán)交給等待隊(duì)列最前面的 Goroutine

當(dāng)互斥鎖處于正常模式時(shí),如果沒有 Goroutine 等待鎖的釋放或者已經(jīng)有被喚醒的 Goroutine 獲得了鎖,會直接返回;在其他情況下會通過喚醒對應(yīng)的 Goroutine;

關(guān)于互斥鎖鎖的使用建議寫業(yè)務(wù)時(shí)不能全局使用同一個(gè) Mutex千萬不要將要加鎖和解鎖分到兩個(gè)以上 Goroutine 中進(jìn)行Mutex 千萬不能被復(fù)制(包括不能通過函數(shù)參數(shù)傳遞),否則會復(fù)制傳參前鎖的狀態(tài):已鎖定 or 未鎖定。很容易產(chǎn)生死鎖,關(guān)鍵是編譯器還發(fā)現(xiàn)不了這個(gè) Deadlock~

RWMutex-讀寫鎖

Go 中 RWMutex 使用的是寫優(yōu)先的設(shè)計(jì)

數(shù)據(jù)結(jié)構(gòu):

type RWMutex struct {
	w           Mutex	//復(fù)用互斥鎖提供的能力
	writerSem   uint32	//writer信號量
	readerSem   uint32	//reader信號量
	readerCount int32	//存儲了當(dāng)前正在執(zhí)行的讀操作數(shù)量
	readerWait  int32	// 表示寫操作阻塞時(shí),等待讀操作完成的個(gè)數(shù)
}

寫鎖

獲取寫鎖 :

  • 調(diào)用結(jié)構(gòu)體持有的Mutex結(jié)構(gòu)體的Mutex.Lock阻塞后續(xù)的寫操作
  • readerCount減少2^30,成為負(fù)數(shù),以阻塞后續(xù)讀操作
  • 如果有其他Goroutine 持有讀鎖,該 Goroutine會進(jìn)入休眠狀態(tài)等待所有讀鎖執(zhí)行結(jié)束后釋放writerSem信號量將當(dāng)前協(xié)程喚醒

釋放寫鎖:

  • readerCount變回正數(shù),釋放讀鎖
  • 喚醒所有因?yàn)樽x鎖而睡眠的Goroutine
  • 調(diào)用Mutex.Unlock 釋放寫鎖

獲取寫鎖時(shí)會先阻塞寫鎖的獲取,后阻塞讀鎖的獲取,這種策略能夠保證讀操作不會被連續(xù)的寫操作『餓死』。

讀鎖

獲取讀鎖

獲取讀鎖的方法 sync.RWMutex.RLock 很簡單,該方法會將readerCount加一:

  • 如果該方法返回負(fù)數(shù)(代表其他 goroutine 獲得了寫鎖,當(dāng)前 goroutine 就會使其陷入休眠等待鎖的釋放
  • 如果該方法返回結(jié)果為非負(fù)數(shù),代表沒有 goroutine 獲得寫鎖,會成功返回

釋放讀鎖

解鎖讀鎖的方法sync.RWMutex.RUnlock,該方法會:

  • readerCount減一,根據(jù)返回值的不同會分別進(jìn)行處理
  • 如果返回值大于等于0,讀鎖直接解鎖成功
  • 如果小于0代表有正在執(zhí)行的寫操作,會調(diào)用sync.RWMutex.rUnlockSlow,將readerWait減一,并且當(dāng)所有讀操作都被釋放后觸發(fā)信號量 writerSem,該信號量被觸發(fā)時(shí),調(diào)度器就會喚醒嘗試獲取寫鎖的 Goroutine

WaitGroup

sync.WaitGroup可以等待一組 Goroutine 的返回

sync.WaitGroup 對外暴露了三個(gè)方法:

方法名 功能
(wg * WaitGroup) Add(delta int) 計(jì)數(shù)器+delta
(wg *WaitGroup) Done() 計(jì)數(shù)器減1
(wg *WaitGroup) Wait() 阻塞直到計(jì)數(shù)器變?yōu)?

sync.WaitGroup.Done只是對 sync.WaitGroup.Add 方法的簡單封裝,相當(dāng)于是加 -1

Sync.Map

Go語言中內(nèi)置的map不是并發(fā)安全的。

Go語言的sync包中提供了一個(gè)開箱即用的并發(fā)安全版map–sync.Map。使用互斥鎖保證并發(fā)安全

數(shù)據(jù)結(jié)構(gòu):

type Map struct {
    mu Mutex
    read atomic.Value // readOnly
    dirty map[interface{}]*entry
    misses int
}

開箱即用表示不用像內(nèi)置的map一樣使用make函數(shù)初始化就能直接使用。同時(shí)sync.Map內(nèi)置了方法:

方法名 功能
(m *sync.Map)Store(key, value interface{}) 保存鍵值對
(m *sync.Map)Load(key interface{}) 根據(jù)key獲取對應(yīng)的值
(m *sync.Map)Delete(key interface{}) 刪除鍵值對
(m *sync.Map)Range(f func(key, value interface{}) bool) 遍歷 sync.Map。Range 的參數(shù)是一個(gè)函數(shù)
*sync.map 沒有Len( ) 方法

原子操作(atomic包)

代碼中的加鎖操作因?yàn)樯婕皟?nèi)核態(tài)的上下文切換會比較耗時(shí)、代價(jià)比較高。針對基本數(shù)據(jù)類型我們還可以使用原子操作來保證并發(fā)安全,因?yàn)樵硬僮魇荊o語言提供的方法它在用戶態(tài)就可以完成,因此性能比加鎖操作更好。Go語言中原子操作由內(nèi)置的標(biāo)準(zhǔn)庫sync/atomic提供。

參考資料:

Go 語言并發(fā)編程、同步原語與鎖 | Go 語言設(shè)計(jì)與實(shí)現(xiàn) (draveness.me)

到此這篇關(guān)于go語言中并發(fā)安全和鎖的文章就介紹到這了,更多相關(guān)go語言中并發(fā)安全和鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于golang?struct?中的?slice?無法原子賦值的問題

    關(guān)于golang?struct?中的?slice?無法原子賦值的問題

    這篇文章主要介紹了為什么?golang?struct?中的?slice?無法原子賦值的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • golang通用的grpc?http基礎(chǔ)開發(fā)框架使用快速入門

    golang通用的grpc?http基礎(chǔ)開發(fā)框架使用快速入門

    這篇文章主要為大家介紹了golang通用的grpc?http基礎(chǔ)開發(fā)框架使用快速入門詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • GO語言中Chan實(shí)現(xiàn)原理的示例詳解

    GO語言中Chan實(shí)現(xiàn)原理的示例詳解

    這篇文章主要為大家詳細(xì)介紹了Go語言中Chan實(shí)現(xiàn)原理的相關(guān)資料,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2023-02-02
  • Go語法糖之‘...’ 的使用實(shí)例詳解

    Go語法糖之‘...’ 的使用實(shí)例詳解

    語法糖(Syntactic sugar),也譯為糖衣語法,指計(jì)算機(jī)語言中添加的某種語法,這種語法對語言的功能并沒有影響,但是更方便程序員使用。這篇文章主要給大家介紹Go語法糖之‘...’ 的使用,感興趣的朋友一起看看吧
    2018-10-10
  • Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究

    Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究

    這篇文章主要為大家介紹了Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Go語言遍歷目錄的三種方法舉例

    Go語言遍歷目錄的三種方法舉例

    學(xué)習(xí)io之后,尤其是文件操作,我們就可以遍歷給定的目錄了,這篇文章主要給大家介紹了關(guān)于Go語言遍歷目錄的三種方法,分別是ioutil.ReadDir、filepath.Walk以及filepath.Glob,需要的朋友可以參考下
    2023-11-11
  • Go數(shù)據(jù)庫遷移的實(shí)現(xiàn)步驟

    Go數(shù)據(jù)庫遷移的實(shí)現(xiàn)步驟

    本文主要介紹了Go數(shù)據(jù)庫遷移的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Go實(shí)現(xiàn)簡易RPC框架的方法步驟

    Go實(shí)現(xiàn)簡易RPC框架的方法步驟

    本文旨在講述 RPC 框架設(shè)計(jì)中的幾個(gè)核心問題及其解決方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-03-03
  • 一步步教你打造高效可靠的Go庫

    一步步教你打造高效可靠的Go庫

    這篇文章主要介紹了一步步教你打造高效可靠的Go庫的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 減少 golang 二進(jìn)制文件大小操作

    減少 golang 二進(jìn)制文件大小操作

    這篇文章主要介紹了減少 golang 二進(jìn)制文件大小操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論