golang并發(fā)安全及讀寫互斥鎖的示例分析
并發(fā)安全和鎖
有時候在Go代碼中可能會存在多個goroutine同時操作一個資源(臨界區(qū)),這種情況會發(fā)生競態(tài)問題(數(shù)據(jù)競態(tài))。類比現(xiàn)實生活中的例子有十字路口被各個方向的的汽車競爭;還有火車上的衛(wèi)生間被車廂里的人競爭。
舉個例子:
var x int64 var wg sync.WaitGroup func add() { for i := 0; i < 5000; i++ { x = x + 1 } wg.Done() } func main() { wg.Add(2) go add() go add() wg.Wait() fmt.Println(x) }
上面的代碼中我們開啟了兩個goroutine去累加變量x的值,這兩個goroutine在訪問和修改x變量的時候就會存在數(shù)據(jù)競爭,導(dǎo)致最后的結(jié)果與期待的不符。
互斥鎖
import ( "fmt" "sync" ) var lock sync.Mutex lock.Lock() // 加鎖 lock.Unlock() // 解鎖
互斥鎖是一種常用的控制共享資源訪問的方法,它能夠保證同時只有一個goroutine可以訪問共享資源。Go語言中使用sync包的Mutex類型來實現(xiàn)互斥鎖。 使用互斥鎖來修復(fù)上面代碼的問題:
var x int64 var wg sync.WaitGroup var lock sync.Mutex func add() { for i := 0; i < 5000; i++ { lock.Lock() // 加鎖 x = x + 1 lock.Unlock() // 解鎖 } wg.Done() } func main() { wg.Add(2) go add() go add() wg.Wait() fmt.Println(x) }
使用互斥鎖能夠保證同一時間有且只有一個goroutine進入臨界區(qū),其他的goroutine則在等待鎖;當互斥鎖釋放后,等待的goroutine才可以獲取鎖進入臨界區(qū),多個goroutine同時等待一個鎖時,喚醒的策略是隨機的。
讀寫互斥鎖
import ( "fmt" "sync" ) var rwlock sync.RWMutex rwlock.Lock() // 加寫鎖 rwlock.Unlock() // 解寫鎖
互斥鎖是完全互斥的,但是有很多實際的場景下是讀多寫少的,當我們并發(fā)的去讀取一個資源不涉及資源修改的時候是沒有必要加鎖的,這種場景下使用讀寫鎖是更好的一種選擇。讀寫鎖在Go語言中使用sync包中的RWMutex類型。
讀寫鎖分為兩種:讀鎖和寫鎖。當一個goroutine獲取讀鎖之后,其他的goroutine如果是獲取讀鎖會繼續(xù)獲得鎖,如果是獲取寫鎖就會等待;當一個goroutine獲取寫鎖之后,其他的goroutine無論是獲取讀鎖還是寫鎖都會等待。
讀寫鎖示例:
var ( x int64 wg sync.WaitGroup lock sync.Mutex rwlock sync.RWMutex ) func write() { // lock.Lock() // 加互斥鎖 rwlock.Lock() // 加寫鎖 x = x + 1 time.Sleep(10 * time.Millisecond) // 假設(shè)讀操作耗時10毫秒 rwlock.Unlock() // 解寫鎖 // lock.Unlock() // 解互斥鎖 wg.Done() } func read() { // lock.Lock() // 加互斥鎖 rwlock.RLock() // 加讀鎖 time.Sleep(time.Millisecond) // 假設(shè)讀操作耗時1毫秒 rwlock.RUnlock() // 解讀鎖 // lock.Unlock() // 解互斥鎖 wg.Done() } func main() { start := time.Now() for i := 0; i < 10; i++ { wg.Add(1) go write() } for i := 0; i < 1000; i++ { wg.Add(1) go read() } wg.Wait() end := time.Now() fmt.Println(end.Sub(start)) }
需要注意的是讀寫鎖非常適合讀多寫少的場景,如果讀和寫的操作差別不大,讀寫鎖的優(yōu)勢就發(fā)揮不出來。
以上就是golang并發(fā)安全及讀寫互斥鎖的示例分析的詳細內(nèi)容,更多關(guān)于golang并發(fā)安全及讀寫互斥鎖的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語言開發(fā)環(huán)境搭建與初探(Windows平臺下)
Go是Google開發(fā)的一種編譯型,並發(fā)型,并具有垃圾回收功能的編程語言,可能很多人想學(xué)習go語言,那么首先就要了解go語言的環(huán)境配置方法2014-10-10Golang源碼分析之golang/sync之singleflight
golang/sync庫拓展了官方自帶的sync庫,提供了errgroup、semaphore、singleflight及syncmap四個包,本次先分析第一個包errgroup的源代碼,下面這篇文章主要給大家介紹了關(guān)于Golang源碼分析之golang/sync之singleflight的相關(guān)資料,需要的朋友可以參考下2022-11-11從基礎(chǔ)到高級全方位解析Go中反射的應(yīng)用
本文我們將全面深入地探討Go語言的反射機制,從反射的基礎(chǔ)概念、為什么需要反射,到如何在Go中實現(xiàn)反射,以及在高級編程場景如泛型編程和插件架構(gòu)中的應(yīng)用,需要的可以參考下2023-10-10解決Go中攔截HTTP流數(shù)據(jù)時字段丟失的問題
在開發(fā)高并發(fā)的Web應(yīng)用時,尤其是在處理HTTP代理和流數(shù)據(jù)攔截的場景下,遇到數(shù)據(jù)丟失的問題并不罕見,最近,在一個項目中,我遇到了一個棘手的問題:在攔截并轉(zhuǎn)發(fā)HTTP流數(shù)據(jù)的過程中,某些數(shù)據(jù)字段因為處理過快而被丟失,所以本文給大家介紹如何解決這個問題2024-08-08