php editor Baicao is here to introduce to you a very useful technique, which is to lock the map for concurrent access. This technique can help developers avoid conflicts and data errors when accessing the map concurrently. By using a locking mechanism, developers can ensure that each request is made in order and that no data clutter occurs. This is very important for developing map operations, especially when multiple users are accessing the map at the same time. Let’s take a look at how to implement this technique!
I have a map: map[string]map[string]*Struct and I need to read/write it in multiple Go routines.
What is the best way to achieve this? Mutex or RWMutex? And where to place it?
If I use RWMutex, should I Lock or RLock before performing operations involving reading and writing?
I tried using rwmutex in the root map, but I'm not sure if that's the best way to solve this problem.
I also tried "locking" before reading and writing, but sometimes I get "concurrent writes" panics.
You can use RWLock. If the operation involves writing (whether it is reading or writing only), you need to use Lock, if it only involves reading, RLock/RUnlock.
Lock can also be considered an exclusive lock. RLock, on the other hand, is non-exclusive. An RLock can be acquired even if the RWMutex is locked for reading, but goroutine execution will be blocked if the resource is locked exclusively by the Lock method:
a blocked Lock call excludes new readers from acquiring the lock
On the other hand, the Lock method blocks goroutine execution until all readers and writers unlock the resource (using the RUnlock/Unlock method). Lock is exclusive because only one goroutine can access the resource (whether reading or writing) until the Unlock method is called.
Typical method:
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) } }
The above is the detailed content of Lock the map for concurrent access to the map. For more information, please follow other related articles on the PHP Chinese website!