Ce face sync.Map.LoadOrStore
LoadOrStore(k, v): dacă cheia există, returnează valoarea existentă și loaded = true; dacă nu, salvează v și returnează v cu loaded = false. Totul se face într-un singur pas, deci dintre mai multe goroutine care încearcă aceeași cheie câștigă exact unul.
LoadAndDelete(k) șterge cheia și returnează valoarea pe care o avea (loaded spune dacă exista). E potrivit pentru „ia o sarcină din listă o singură dată”. Swap(k, v) pune valoarea nouă și returnează valoarea veche, dacă exista.
Ce returnează
Valoarea (any) și un bool care spune dacă cheia exista deja.
Exemple
Exemplul 1: Cele trei operații pe rând
package main
import (
"fmt"
"sync"
)
func main() {
var sesiuni sync.Map
v, existent := sesiuni.LoadOrStore("ana", "sesiune-1")
fmt.Println("LoadOrStore ana:", v, existent)
v, existent = sesiuni.LoadOrStore("ana", "sesiune-2")
fmt.Println("LoadOrStore ana:", v, existent)
vechi, existent := sesiuni.Swap("ana", "sesiune-3")
fmt.Println("Swap ana: ", vechi, existent)
v, existent = sesiuni.LoadAndDelete("ana")
fmt.Println("LoadAndDelete: ", v, existent)
v, existent = sesiuni.LoadAndDelete("ana")
fmt.Println("Din nou: ", v, existent)
}
Rezultat
LoadOrStore ana: sesiune-1 false
LoadOrStore ana: sesiune-1 true
Swap ana: sesiune-1 true
LoadAndDelete: sesiune-3 true
Din nou: <nil> false
Exemplul 2: Un singur câștigător dintre 20 de goroutine
Toate încearcă să rezerve locul 12A; LoadOrStore garantează că exact una reușește.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var locuri sync.Map
var reusite, refuzate atomic.Int32
var wg sync.WaitGroup
for i := 1; i <= 20; i++ {
wg.Go(func() {
_, ocupat := locuri.LoadOrStore("12A", fmt.Sprintf("client %d", i))
if ocupat {
refuzate.Add(1)
} else {
reusite.Add(1)
}
})
}
wg.Wait()
fmt.Println("Rezervări reușite:", reusite.Load())
fmt.Println("Rezervări refuzate:", refuzate.Load())
}
Rezultat
Rezervări reușite: 1
Rezervări refuzate: 19
Greșeli frecvente
- Creezi o valoare scumpă înainte de fiecare
LoadOrStore(o conexiune, un fișier deschis), deși de cele mai multe ori cheia există deja. Fă întâi unLoadși creează valoarea doar dacă lipsește, apoiLoadOrStore.
Comenzi înrudite
sync.Map: Un map sigur pentru goroutine fără mutex extern: Store, Load, Delete, Range și Clear pot fi apelate concurent.sync.Map.CompareAndSwap: Schimbă (CompareAndSwap) sau șterge (CompareAndDelete) o cheie doar dacă valoarea ei este încă cea așteptată.sync/atomic.Int32: Un int32 cu operații atomice (Add, Load, Store, Swap, CompareAndSwap); la fel ca atomic.Int64, dar pe 32 de biți.