php小編百草在這里向大家介紹一種非常有用的技巧,即鎖定地圖并發(fā)訪問的地圖。這個技巧可以幫助開發(fā)者在并發(fā)訪問地圖時避免沖突和數據錯誤。通過使用鎖定機制,開發(fā)者可以確保每個請求都能按順序進行,并且不會出現數據混亂的情況。這對于開發(fā)中的地圖操作非常重要,特別是在多個用戶同時訪問地圖時。下面讓我們一起來了解一下如何實現這個技巧吧!
問題內容
我有一個地圖:map[string]map[string]*Struct,我需要在多個 Go 例程中讀取/寫入它。
實現這一目標的最佳方法是什么?互斥體或 RWMutex ?以及放置在哪里?
如果我使用 RWMutex,那么在執(zhí)行涉及讀和寫的操作之前我應該??鎖定還是 RLock?
我嘗試在根映射中使用 rwmutex,但我不確定這是否是解決此問題的最佳方法。
我還嘗試在讀寫之前“鎖定”,但有時會收到“并發(fā)寫入”恐慌。
解決方法
您可以使用RWLock。如果操作涉及到寫(不管是讀還是只寫)就需要使用Lock,如果只涉及讀則RLock/RUnlock。
Lock也可以被認為是獨占鎖。另一方面,RLock 是非排他性的。
即使 RWMutex 已被鎖定以進行讀取,也可以獲取 RLock,但如果資源被 Lock 方法獨占鎖定,則會阻止 goroutine 執(zhí)行:
a blocked Lock call excludes new readers from acquiring the lock
登錄后復制
另一方面,Lock 方法會阻止 goroutine 執(zhí)行,直到所有讀取器和寫入器解鎖資源(使用 RUnlock/Unlock 方法)。 Lock 是獨占的,因為在調用 Unlock 方法之前,只有一個 goroutine 可以訪問資源(無論是讀還是寫)。
典型方法:
package main import ( "fmt" "sync" ) type SomeStruct struct { someInfo string } type ConcurrentStruct struct { mu sync.RWMutex data map[string]map[string]*SomeStruct } func New() *ConcurrentStruct { return &ConcurrentStruct{ data: make(map[string]map[string]*SomeStruct), } } func (cs *ConcurrentStruct) Set(key1, key2 string, val SomeStruct) { cs.mu.Lock() defer cs.mu.Unlock() if _, ok := cs.data[key1]; !ok { cs.data[key1] = make(map[string]*SomeStruct) } cs.data[key1][key2] = &val } func (cs *ConcurrentStruct) Get(key1, key2 string) (val *SomeStruct, ok bool) { cs.mu.RLock() defer cs.mu.RUnlock() if _, ok := cs.data[key1]; ok { val, ok := cs.data[key1][key2] return val, ok } return nil, false } func main() { cs := New() cs.Set("a", "b", SomeStruct{"Hello, World!"}) if _, ok := cs.Get("a", "c"); !ok { fmt.Printf("key1=a, key2=c, not found\n") } if s, ok := cs.Get("a", "b"); ok { fmt.Printf("key1=a, key2=b, found: %v\n", s) } }
登錄后復制