package main import ( "fmt" "math/rand" "sync" "time" ) //全局變量 var count int var rLock sync.RWMutex func Read(i int) { rLock.RLock() fmt.Printf("讀 goroutine%d 數據=%d\n", i, count) defer rLock.RUnlock() } func Write(i int) { rLock.Lock() count = rand.Intn(1000) fmt.Printf("寫 goroutine%d 數據=%d\n", i, count) defer rLock.Unlock() } func main() { for i := 0; i < 5; i++ { go Write(i) } for i := 0; i < 5; i++ { go Read(i) } time.Sleep(time.Second * 2) //執行結果: /* 寫 goroutine0 數據=81 寫 goroutine1 數據=887 讀 goroutine1 數據=887 寫 goroutine3 數據=847 寫 goroutine4 數據=59 讀 goroutine0 數據=59 讀 goroutine3 數據=59 寫 goroutine2 數據=81 讀 goroutine4 數據=81 讀 goroutine2 數據=81 */ }
互斥鎖的本質是當一個goroutine訪問的時候,其他goroutine都不能訪問。這樣在資源同步,避免競爭的同時也降低了程序的並發性能。程序由原來的並行執行變成了串行執行。
其實,當我們對一個不會變化的數據只做“讀”操作的話,是不存在資源競爭的問題的。因為數據是不變的,不管怎么讀取,多少goroutine同時讀取,都是可以的。
所以問題不是出在“讀”上,主要是修改,也就是“寫”。修改的數據要同步,這樣其他goroutine才可以感知到。所以真正的互斥應該是讀取和修改、修改和修改之間,讀和讀是沒有互斥操作的必要的。
因此,衍生出另外一種鎖,叫做讀寫鎖。
讀寫鎖可以讓多個讀操作並發,同時讀取,但是對於寫操作是完全互斥的。也就是說,當一個goroutine進行寫操作的時候,其他goroutine既不能進行讀操作,也不能進行寫操作。