Sobes.tech
Middle+

Jak chronić się przed błędami podczas równoczesnego zapisu w mapie?

sobes.tech AI

Odpowiedź od AI

Aby chronić się przed błędami podczas równoczesnego zapisu do map w Golang, które domyślnie nie są bezpieczne dla wątków, używa się następujących mechanizmów:

  • sync.Mutex: Blokuje mapę przed zapisem i odblokowuje po.

    import "sync"
    
    type SafeMap struct {
        mu sync.Mutex
        data map[string]int
    }
    
    func NewSafeMap() *SafeMap {
        return &SafeMap{
            data: make(map[string]int),
        }
    }
    
    func (sm *SafeMap) Set(key string, value int) {
        sm.mu.Lock()
        defer sm.mu.Unlock()
        sm.data[key] = value
    }
    
    func (sm *SafeMap) Get(key string) (int, bool) {
        sm.mu.Lock()
        defer sm.mu.Unlock()
        val, ok := sm.data[key]
        return val, ok
    }
    
  • sync.RWMutex: Pozwala na jednoczesne czytanie z mapy przez wiele gorutyn, ale blokuje zapis podczas odczytu lub zapisu równoczesnego.

    import "sync"
    
    type SafeMapRWMutex struct {
        mu sync.RWMutex
        data map[string]int
    }
    
    func NewSafeMapRWMutex() *SafeMapRWMutex {
        return &SafeMapRWMutex{
            data: make(map[string]int),
        }
    }
    
    func (sm *SafeMapRWMutex) Set(key string, value int) {
        sm.mu.Lock() // Blokada zapisu
        defer sm.mu.Unlock()
        sm.data[key] = value
    }
    
    func (sm *SafeMapRWMutex) Get(key string) (int, bool) {
        sm.mu.RLock() // Blokada odczytu
        defer sm.mu.RUnlock()
        val, ok := sm.data[key]
        return val, ok
    }
    
  • sync.Map: Specjalistyczny, bezpieczny dla wielu wątków typ, zoptymalizowany dla scenariuszy, w których zestaw kluczy jest stosunkowo stabilny, a zapisy są rzadkie, lub gdy wiele gorutyn odczytuje i zapisuje dla rozłącznych zestawów kluczy.

    import "sync"
    
    var safeMap sync.Map // Deklaracja
    
    func UseSyncMap() {
        safeMap.Store("key1", 10) // Zapis
        if val, ok := safeMap.Load("key1"); ok { // Odczyt
            // Użyj val
        }
        safeMap.Delete("key1") // Usunięcie
    }
    

Porównanie podejść:

Mechanizm Zalety Wady Zastosowanie
sync.Mutex Prosty w użyciu Blokuje wszystkie operacje podczas zapisu Proste scenariusze, w których konkurencyjność nie jest wysoka lub odczyt/zapis są podobne.
sync.RWMutex Pozwala na równoczesne odczyty Bardziej skomplikowany niż sync.Mutex. Zapis blokuje odczyt i inne zapisy. Scenariusze z częstym odczytem i rzadkim zapisem.
sync.Map Optymalizowany dla określonych scenariuszy Ma ograniczone API. Może być wolniejszy niż Mutex, jeśli dostęp jest całkowicie losowy. Scenariusze z relatywnie stabilnymi kluczami lub rozłącznymi zestawami kluczy dla różnych gorutyn.

Wybór konkretnego podejścia zależy od charakteru równoczesnego dostępu do mapy. Dla ogólnych przypadków często wystarczy sync.Mutex lub sync.RWMutex. Dla specyficznych scenariuszy sync.Map może zapewnić lepszą wydajność.