Middle
Ką reikia prisiminti dirbant su mutex'ais Go?
sobes.tech AI
Atsakymas iš AI
Dirbant su mutex (sync.Mutex) Go kalboje svarbu atsiminti šiuos dalykus:
- Užrakinimas ir atlaisvinimas: Mutex būtina užrakinti (
Lock()) prieš prieigą prie bendro naudojimo duomenų ir atlaisvinti (Unlock()) po darbo su jais pabaigos. Naudojimasdefer mu.Unlock()iškart pomu.Lock()yra gera praktika, padedanti išvengti užmirštų atlaisvinimų. - Sinchronizacijos garantija: Mutex suteikia išskirtinę prieigą prie ištekliaus vienu metu tik vienai gorutinai.
- "Užrakinta/atsidengusi" būklė: Pakartotinis
Lock()iškvietimas jau užrakintame mutexe sukels blokuojamąją gorutiną, kol kita gorutina neišlaisvins mutexo.Unlock()iškvietimas neužrakintame mutexe sukels paniką vykdymo metu. - Nekopijuokite mutexų: Struktūra
sync.Mutexnėra skirta kopijavimui po pirmojo naudojimo. Perdavimas mutexo reikšme į funkciją arba struktūros kopijavimas, turinčios mutexą, gali sukelti netinkamą sinchronizaciją ir paniką. - Deadlock (užstrigimas): Atsitinka, kai dvi ar daugiau gorutinų laukia viena kitos, kad atlaisvintų išteklius. Tipinis scenarijus: gorutina A užrakina R1 išteklių ir laukia R2, o gorutina B užrakina R2 ir laukia R1.
- Livelock (gyvas užraktas): Situacija, kai gorutinos nuolat keičia savo būseną atsakydamos viena į kitą, bet nedaro naudingo darbo ir nepaeina į priekį. Tai retesnė nei deadlock.
- Badavimas: Situacija, kai viena ar kelios gorutinos negali pasiekti bendro ištekliaus dėl nuolatinio kitų gorutinų jo užėmimo. Go mutexuose badavimas nėra garantuotas.
- Naudojant
sync.RWMutexskaitymui/rašymui: Jei dauguma operacijų yra skaitymas, o rašymas retas,sync.RWMutexgali būti efektyvesnis. Jis leidžia kelioms gorutinoms skaityti vienu metu, bet rašymo metu blokuoja ir skaitymą, ir kitus rašymus. - Trumpi užraktai: Stenkitės laikyti užraktus kuo trumpiau. Kuo ilgiau mutexas užrakintas, tuo didesnė tikimybė, kad kitos gorutinos lauks, kas mažina paralelizmą.
- Testavimas dėl varžybų: Naudojant
-racežymeklįgo testkūrimo ir paleidimo metu, galima aptikti varžybas, dažnai sukeltas netinkamo mutexų naudojimo.
Pavyzdys naudojant defer:
import (
"sync"
)
type SafeCounter struct {
mu sync.Mutex
v map[string]int
}
// Inc saugiai padidina skaitiklį nurodytu raktu.
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
// Atidėk atlaisvinimą iki funkcijos pabaigos.
defer c.mu.Unlock()
c.v[key]++
}
// Value grąžina dabartinę skaitiklio reikšmę nurodytu raktu.
func (c *SafeCounter) Value(key string) int {
c.mu.Lock()
// Atidėk atlaisvinimą po reikšmės gavimo.
defer c.mu.Unlock()
return c.v[key]
}