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