Ответ
Для создания потокобезопасной map
в Go используйте sync.Mutex
или, что чаще всего предпочтительнее для карт, sync.RWMutex
(если нужны раздельные блокировки на чтение/запись). sync.RWMutex
позволяет множеству горутин читать карту одновременно, но блокирует все операции при записи.
Пример использования sync.RWMutex
:
package main
import (
"fmt"
"sync"
)
type SafeMap struct {
sync.RWMutex
data map[string]interface{}
}
// NewSafeMap создает новый экземпляр SafeMap
func NewSafeMap() *SafeMap {
return &SafeMap{
data: make(map[string]interface{}),
}
}
// Get безопасно извлекает значение по ключу, возвращая значение и флаг наличия
func (sm *SafeMap) Get(key string) (interface{}, bool) {
sm.RLock() // Блокировка для чтения
defer sm.RUnlock() // Разблокировка после завершения чтения
val, ok := sm.data[key]
return val, ok
}
// Set безопасно устанавливает значение по ключу
func (sm *SafeMap) Set(key string, value interface{}) {
sm.Lock() // Блокировка для записи
defer sm.Unlock() // Разблокировка после завершения записи
sm.data[key] = value
}
// Delete безопасно удаляет значение по ключу
func (sm *SafeMap) Delete(key string) {
sm.Lock()
defer sm.Unlock()
delete(sm.data, key)
}
func main() {
m := NewSafeMap()
// Пример использования
m.Set("name", "Alice")
m.Set("age", 30)
if val, ok := m.Get("name"); ok {
fmt.Printf("Name: %vn", val)
}
if val, ok := m.Get("age"); ok {
fmt.Printf("Age: %vn", val)
}
if _, ok := m.Get("city"); !ok {
fmt.Println("City not found (as expected).")
}
m.Delete("age")
if _, ok := m.Get("age"); !ok {
fmt.Println("Age deleted.")
}
}
Ключевые моменты:
- Встраивание
sync.RWMutex
:sync.RWMutex
встраивается в структуруSafeMap
. Это позволяет напрямую вызывать методы мьютекса (Lock
,Unlock
,RLock
,RUnlock
) на экземпляреSafeMap
. - Защита всех операций: Все операции, которые модифицируют или читают
map
(Get
,Set
,Delete
), должны быть защищены мьютексом. defer
для гарантированного разблокирования: Использованиеdefer
гарантирует, что мьютекс будет разблокирован (Unlock()
илиRUnlock()
) после завершения функции, даже если произойдет паника.RWMutex
для параллельных чтений:sync.RWMutex
является более эффективным выбором, чем простойsync.Mutex
, для карт, так как он позволяет множеству горутин читать данные одновременно (RLock()
), но при этом обеспечивает эксклюзивный доступ для операций записи (Lock()
).- Альтернатива
sync.Map
: Для некоторых специфических сценариев (например, когда преобладают чтения, а записи редки и не конфликтуют по ключам) можно использовать встроенныйsync.Map
, который оптимизирован для таких нагрузок и не требует явного управления мьютексами.