Go 互斥鎖和讀寫互斥鎖的實(shí)現(xiàn)
先來看這樣一段代碼,所存在的問題:
var wg sync.WaitGroup var x int64 func main() { wg.Add(2) go f() go f() wg.Wait() fmt.Println(x) // 輸出:12135 } func f() { for i:=0;i<10000;i++ { x = x+1 } wg.Done() }
這里為什么輸出是 12135(不同的機(jī)器結(jié)果不一樣),而不是20000。
因?yàn)?x 的賦值,總共分為三個(gè)步驟:取出x的值、計(jì)算x的結(jié)果、給x賦值。那么由于對(duì)于f函數(shù)的調(diào)用采用了goroutine協(xié)程,所以存在資源競(jìng)爭(zhēng)的問題,所以有賦值和計(jì)算過程中存在臟數(shù)據(jù)。對(duì)于此類的問題,可以采用互斥鎖解決:
互斥鎖
互斥鎖是一種常用的控制共享資源訪問的方法,它能夠保證同時(shí)只有一個(gè)goroutine可以訪問共享資源。Go語言中使用sync包的Mutex類型來實(shí)現(xiàn)互斥鎖。
var wg sync.WaitGroup var x int64 var lock sync.Mutex func main() { wg.Add(2) go f() go f() wg.Wait() fmt.Println(x) // 輸出:20000 } func f() { for i:=0;i<10000;i++ { lock.Lock() // 加互斥鎖 x = x+1 lock.Unlock() // 解鎖 } wg.Done() }
使用互斥鎖能夠保證同一時(shí)間有且只有一個(gè)goroutine進(jìn)入臨界區(qū),其他的goroutine則在等待鎖;當(dāng)互斥鎖釋放后,等待的goroutine才可以獲取鎖進(jìn)入臨界區(qū),多個(gè)goroutine同時(shí)等待一個(gè)鎖時(shí),喚醒的策略是隨機(jī)的。
讀寫互斥鎖
互斥鎖是完全互斥的,但是有很多實(shí)際的場(chǎng)景下是讀多寫少的,當(dāng)我們并發(fā)的去讀取一個(gè)資源不涉及資源修改的時(shí)候是沒有必要加鎖的,這種場(chǎng)景下使用讀寫鎖是更好的一種選擇。讀寫鎖在Go語言中使用sync包中的RWMutex類型。
讀寫鎖分為兩種:讀鎖和寫鎖。當(dāng)一個(gè)goroutine獲取讀鎖之后,其他的goroutine如果是獲取讀鎖會(huì)繼續(xù)獲得鎖,如果是獲取寫鎖就會(huì)等待;當(dāng)一個(gè)goroutine獲取寫鎖之后,其他的goroutine無論是獲取讀鎖還是寫鎖都會(huì)等待。
var ( x1 int64 wg1 sync.WaitGroup lock1 sync.Mutex rwlock sync.RWMutex ) func main() { startTime := time.Now() for i:=0;i<100;i++ { wg1.Add(1) write() } for i:=0;i<10000;i++ { wg1.Add(1) read() } wg1.Wait() fmt.Println(time.Now().Sub(startTime)) // 互斥鎖用時(shí): 973.9304ms // 讀寫互斥鎖用時(shí): 718.094ms } func read() { defer wg1.Done() //lock1.Lock() // 互斥鎖 rwlock.RLock() // 讀寫互斥鎖 fmt.Println(x1) //lock1.Unlock() // 互斥鎖 rwlock.RUnlock() // 讀寫互斥鎖 } func write() { defer wg1.Done() lock1.Lock() x1 = x1+1 lock1.Unlock() }
到此這篇關(guān)于Go 互斥鎖和讀寫互斥鎖的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Go 互斥鎖和讀寫互斥鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go簡(jiǎn)單實(shí)現(xiàn)協(xié)程方法
本文主要介紹了Go簡(jiǎn)單實(shí)現(xiàn)協(xié)程的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-12-12Go語言構(gòu)建流數(shù)據(jù)pipeline的示例詳解
Go的并發(fā)原語可以輕松構(gòu)建流數(shù)據(jù)管道,從而高效利用?I/O?和多個(gè)?CPU,?本文展示了此類pipelines的示例,強(qiáng)調(diào)了操作失敗時(shí)出現(xiàn)的細(xì)微之處,并介紹了干凈地處理失敗的技術(shù),希望對(duì)大家有所幫助2024-02-02Golang操作MySql數(shù)據(jù)庫的完整步驟記錄
這篇文章主要給大家介紹了關(guān)于Golang操作MySql數(shù)據(jù)庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11詳解如何使用go-acme/lego實(shí)現(xiàn)自動(dòng)簽發(fā)證書
這篇文章主要為大家詳細(xì)介紹了如何使用?go-acme/lego?的客戶端或庫完成證書的自動(dòng)簽發(fā),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03go語言net包rpc遠(yuǎn)程調(diào)用的使用示例
本篇文章主要介紹了go語言net包rpc遠(yuǎn)程調(diào)用的使用示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11