Go 互斥鎖和讀寫互斥鎖的實現(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(不同的機器結(jié)果不一樣),而不是20000。
因為 x 的賦值,總共分為三個步驟:取出x的值、計算x的結(jié)果、給x賦值。那么由于對于f函數(shù)的調(diào)用采用了goroutine協(xié)程,所以存在資源競爭的問題,所以有賦值和計算過程中存在臟數(shù)據(jù)。對于此類的問題,可以采用互斥鎖解決:
互斥鎖
互斥鎖是一種常用的控制共享資源訪問的方法,它能夠保證同時只有一個goroutine可以訪問共享資源。Go語言中使用sync包的Mutex類型來實現(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()
}
使用互斥鎖能夠保證同一時間有且只有一個goroutine進(jìn)入臨界區(qū),其他的goroutine則在等待鎖;當(dāng)互斥鎖釋放后,等待的goroutine才可以獲取鎖進(jìn)入臨界區(qū),多個goroutine同時等待一個鎖時,喚醒的策略是隨機的。
讀寫互斥鎖
互斥鎖是完全互斥的,但是有很多實際的場景下是讀多寫少的,當(dāng)我們并發(fā)的去讀取一個資源不涉及資源修改的時候是沒有必要加鎖的,這種場景下使用讀寫鎖是更好的一種選擇。讀寫鎖在Go語言中使用sync包中的RWMutex類型。
讀寫鎖分為兩種:讀鎖和寫鎖。當(dāng)一個goroutine獲取讀鎖之后,其他的goroutine如果是獲取讀鎖會繼續(xù)獲得鎖,如果是獲取寫鎖就會等待;當(dāng)一個goroutine獲取寫鎖之后,其他的goroutine無論是獲取讀鎖還是寫鎖都會等待。
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))
// 互斥鎖用時: 973.9304ms
// 讀寫互斥鎖用時: 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 互斥鎖和讀寫互斥鎖的實現(xiàn)的文章就介紹到這了,更多相關(guān)Go 互斥鎖和讀寫互斥鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一站式解決方案:在Windows和Linux上快速搭建Go語言開發(fā)環(huán)境
本文將介紹如何在Windows和Linux操作系統(tǒng)下搭建Go語言開發(fā)環(huán)境,以幫助您更高效地進(jìn)行Go語言開發(fā),需要的朋友可以參考下2023-10-10
Go語言同步等待組sync.WaitGroup結(jié)構(gòu)體對象方法詳解
這篇文章主要為大家介紹了Go語言同步等待組sync.WaitGroup結(jié)構(gòu)體對象方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

