Go讀寫(xiě)鎖操作方法示例詳解
引言
前面講到,在資源競(jìng)爭(zhēng)的時(shí)候可以使用互斥鎖,保證了資源訪問(wèn)的唯一性,但也降低了性能,仔細(xì)分析一下場(chǎng)景,如果只是讀取數(shù)據(jù),無(wú)論多少個(gè)goroutine都是不會(huì)存在邏輯上的互斥操作的。
這里讀寫(xiě)鎖?? RWMutex就應(yīng)運(yùn)而生了,RWMutex可以分別針對(duì)讀操作和寫(xiě)操作進(jìn)行上鎖和解鎖。
RWMutex同一時(shí)刻允許多個(gè)讀操作進(jìn)行,但只允許一個(gè)寫(xiě)操作進(jìn)行,同時(shí),在某一個(gè)寫(xiě)操作進(jìn)行的時(shí)候,讀操作不可進(jìn)行。
讀寫(xiě)鎖有很多方法
- 方法一: RLock 這個(gè)方法是讀鎖,當(dāng)寫(xiě)鎖存在的時(shí)候,無(wú)法加載讀鎖,只有當(dāng)不存在鎖,或者只有讀鎖的時(shí)候才能使用。讀鎖可以同時(shí)加載多個(gè),適用于多度寫(xiě)少的場(chǎng)景。
- 方法二: RUnlock 這個(gè)方法是讀解鎖,用來(lái)撤銷單次的讀鎖操作。
- 方法三: Lock 這個(gè)方法是寫(xiě)上鎖,如果在添加寫(xiě)上鎖之前已經(jīng)有其他的讀鎖和寫(xiě)鎖了,此時(shí),這個(gè)Lock會(huì)被阻塞,直到可以使用。
- 方法四: Unlock 這個(gè)方法是寫(xiě)解鎖,如果沒(méi)有綁定寫(xiě)鎖就直接寫(xiě)解鎖,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。
讀操作
下面用實(shí)際的代碼做例子,看一下讀操作:
package main import ( "fmt" "sync" "time" ) //新建一個(gè)鎖對(duì)象的指針,然后待會(huì)兒再指針中創(chuàng)建這個(gè)鎖的對(duì)象 var rwMutex *sync.RWMutex //為了保證 子的goroutine先執(zhí)行,可以使用同步等待組wg,這里創(chuàng)建wg的指針類型 var wg *sync.WaitGroup func main() { rwMutex = new(sync.RWMutex) wg = new(sync.WaitGroup) wg.Add(2)//這里記得+add // 在主函數(shù)中 啟動(dòng)2條goroutine go readData(1) go readData(2) wg.Wait() fmt.Println("main func end") } func readData(i int) { defer wg.Done() fmt.Println(i, "start locking!") // 給讀操作 上鎖 rwMutex.RLock() // 讀數(shù)據(jù) fmt.Println(i, "Reading data") // 睡一下 time.Sleep(1 * time.Second) // 讀解鎖 rwMutex.RUnlock() //打印提示信息 fmt.Println(i, "Read over") }
代碼運(yùn)行結(jié)果如下:
2 start locking!
2 Reading data
1 start locking!
1 Reading data
2 Read over
1 Read over
main func end
從打印結(jié)果可知,第二條goroutine先上讀鎖,然后第二條開(kāi)始讀取,然后第一條上讀鎖【從這里就可以看出,因?yàn)榈诙l的讀鎖還沒(méi)讀解鎖,第一條的讀鎖就上了,所以這里的讀鎖并不互斥】,之后第一條開(kāi)始讀取,第二條讀解鎖,第一條讀解鎖。主goroutine結(jié)束。
寫(xiě)操作
package main import ( "fmt" "sync" "time" ) //新建一個(gè)鎖對(duì)象的指針,然后待會(huì)兒再指針中創(chuàng)建這個(gè)鎖的對(duì)象 var rwMutex *sync.RWMutex //為了保證 子的goroutine先執(zhí)行,可以使用同步等待組wg,這里創(chuàng)建wg的指針類型 var wg *sync.WaitGroup func main() { rwMutex = new(sync.RWMutex) wg = new(sync.WaitGroup) wg.Add(4) // 在主函數(shù)中 啟動(dòng)2條goroutine go readData(1) go readData(2) go writeData(3) go writeData(4) wg.Wait() fmt.Println("main func end") } func readData(i int) { defer wg.Done() fmt.Println(i, "start locking!") // 給讀操作 上鎖 rwMutex.RLock() // 讀數(shù)據(jù) fmt.Println(i, "Reading data") // 睡一下 time.Sleep(1 * time.Second) // 讀解鎖 rwMutex.RUnlock() //打印提示信息 fmt.Println(i, "Read over") } func writeData(i int) { defer wg.Done() fmt.Println(i, " Writing Start") //寫(xiě)上鎖 rwMutex.Lock() fmt.Println(i, "~~~ writing right now~~~") time.Sleep(1 * time.Second) rwMutex.Unlock() fmt.Println(i, "writing completed") }
代碼運(yùn)行結(jié)果如下:
2 start locking!
2 Reading data
4 Writing Start
1 start locking!
3 Writing Start
2 Read over
4 ~~~ writing right now~~~
4 writing completed
1 Reading data
1 Read over
3 ~~~ writing right now~~~
3 writing completed
main func end
分析可知,只有在goroutine4結(jié)束寫(xiě)之后goroutine3才拿到權(quán)限開(kāi)始寫(xiě)。
不過(guò)講真,到處都是lock 和 unlock,臨界區(qū)什么的,真的是臃腫又容易出問(wèn)題。
go語(yǔ)言中多個(gè)協(xié)程想共享數(shù)據(jù)的時(shí)候,將會(huì)有更加優(yōu)雅的處理方式。
以上就是Go讀寫(xiě)鎖方法示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Go讀寫(xiě)鎖方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang 實(shí)現(xiàn)簡(jiǎn)單隨機(jī)負(fù)載均衡
均衡算法又分為 隨機(jī),輪詢,加權(quán)輪詢,哈希,而隨機(jī)負(fù)載均衡算法就是本文的重點(diǎn),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06go語(yǔ)言處理JSON和XML數(shù)據(jù)示例解析
這篇文章主要介紹了go語(yǔ)言處理JSON和XML數(shù)據(jù)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Go語(yǔ)言中基本數(shù)據(jù)類型的相互轉(zhuǎn)換詳解
Go在不同類型的變量之間賦值時(shí)需要顯示轉(zhuǎn)換,不能自動(dòng)轉(zhuǎn)換。這篇文章主要和大家介紹了Go語(yǔ)言中基本數(shù)據(jù)類型的相互轉(zhuǎn)換,感興趣的小伙伴可以了解一下2022-10-10GO語(yǔ)言協(xié)程創(chuàng)建使用并通過(guò)channel解決資源競(jìng)爭(zhēng)
這篇文章主要為大家介紹了GO語(yǔ)言協(xié)程創(chuàng)建使用并通過(guò)channel解決資源競(jìng)爭(zhēng),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04Golang實(shí)現(xiàn)http文件上傳小功能的案例
這篇文章主要介紹了Golang實(shí)現(xiàn)http文件上傳小功能的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05Go使用database/sql操作數(shù)據(jù)庫(kù)的教程指南
Go?語(yǔ)言中,有一個(gè)名為database/sql的標(biāo)準(zhǔn)庫(kù),提供了統(tǒng)一的編程接口,使開(kāi)發(fā)人員能夠以一種通用的方式與各種關(guān)系型數(shù)據(jù)庫(kù)進(jìn)行交互,本文就來(lái)和大家講講它的具體操作吧2023-06-06使用golang實(shí)現(xiàn)一個(gè)MapReduce的示例代碼
這篇文章主要給大家介紹了關(guān)于如何使用golang實(shí)現(xiàn)一個(gè)MapReduce,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09