2015-12-09 07:45:11 +00:00
## 9.3. sync.RWMutex讀寫鎖
2016-01-02 12:56:29 +00:00
在100刀的存款消失時不做記録多少還是會讓我們有一些恐慌, Bob寫了一個程序, 每秒運行幾百次來檢査他的銀行餘額。他會在家, 在工作中, 甚至會在他的手機上來運行這個程序。銀行註意到這些陡增的流量使得存款和取款有了延時, 因爲所有的餘額査詢請求是順序執行的, 這樣會互斥地獲得鎖, 併且會暫時阻止其它的goroutine運行。
2016-01-01 14:45:35 +00:00
2016-01-02 12:56:29 +00:00
由於Balance函數隻需要讀取變量的狀態, 所以我們同時讓多個Balance調用併發運行事實上是安全的, 隻要在運行的時候沒有存款或者取款操作就行。在這種場景下我們需要一種特殊類型的鎖, 其允許多個隻讀操作併行執行, 但寫操作會完全互斥。這種鎖叫作“多讀單寫”鎖(multiple readers, single writer lock), Go語言提供的這樣的鎖是sync.RWMutex:
2016-01-01 14:45:35 +00:00
```go
var mu sync.RWMutex
var balance int
func Balance() int {
2016-01-21 02:44:23 +00:00
mu.RLock() // readers lock
defer mu.RUnlock()
return balance
2016-01-01 14:45:35 +00:00
}
```
2016-01-02 12:56:29 +00:00
Balance函數現在調用了RLock和RUnlock方法來獲取和釋放一個讀取或者共享鎖。Deposit函數沒有變化, 會調用mu.Lock和mu.Unlock方法來獲取和釋放一個寫或互斥鎖。
2016-01-01 14:45:35 +00:00
2016-01-02 12:56:29 +00:00
在這次脩改後, Bob的餘額査詢請求就可以彼此併行地執行併且會很快地完成了。鎖在更多的時間范圍可用, 併且存款請求也能夠及時地被響應了。
2016-01-01 14:45:35 +00:00
2016-01-02 12:56:29 +00:00
RLock隻能在臨界區共享變量沒有任何寫入操作時可用。一般來説, 我們不應該假設邏輯上的隻讀函數/方法也不會去更新某一些變量。比如一個方法功能是訪問一個變量,但它也有可能會同時去給一個內部的計數器+1(譯註:可能是記録這個方法的訪問次數啥的),或者去更新緩存--使卽時的調用能夠更快。如果有疑惑的話,請使用互斥鎖。
2016-01-01 14:45:35 +00:00
2016-01-18 03:22:04 +00:00
RWMutex隻有當獲得鎖的大部分goroutine都是讀操作, 而鎖在競爭條件下, 也就是説, goroutine們必須等待才能獲取到鎖的時候, RWMutex才是最能帶來好處的。RWMutex需要更複雜的內部記録, 所以會讓它比一般的無競爭鎖的mutex慢一些。
2016-01-01 14:45:35 +00:00