Middle
Wat moet je onthouden bij het werken met mutexen in Go?
sobes.tech AI
Antwoord van AI
Bij het werken met mutexen (sync.Mutex) in Go is het belangrijk om het volgende te onthouden:
- Vastleggen en vrijgeven: De mutex moet verplicht worden vastgelegd (
Lock()) voordat toegang wordt verkregen tot gedeelde gegevens en vrijgegeven (Unlock()) nadat het werk is voltooid. Het gebruik vandefer mu.Unlock()direct namu.Lock()is een goede praktijk om vergeten te voorkomen. - Uitsluitend toegang: De mutex biedt exclusieve toegang tot een resource aan één goroutine tegelijk.
- "Geblokkeerd/ontblokt"-status: Het opnieuw aanroepen van
Lock()op een al geblokkeerde mutex zal de oproepende goroutine blokkeren totdat deze door een andere wordt vrijgegeven. Het aanroepen vanUnlock()op een niet-gebroken mutex veroorzaakt een panic tijdens uitvoering. - Mutexen niet kopiëren: De structuur
sync.Mutexis niet bedoeld om te worden gekopieerd na het eerste gebruik. Het doorgeven van een mutex per waarde of het kopiëren van de structuur die de mutex bevat, kan leiden tot onjuiste synchronisatie en panics. - Deadlocks (doodlopende blokkades): Ontstaan wanneer twee of meer goroutines op elkaar wachten om resources vrij te geven. Typisch scenario: goroutine A blokkeert R1 en wacht op R2, terwijl goroutine B R2 blokkeert en wacht op R1.
- Livelocks (levende blokkades): Situatie waarin goroutines voortdurend van status veranderen als reactie op elkaars acties, zonder nuttig werk te verrichten of vooruitgang te boeken. Dit komt minder vaak voor dan deadlock.
- Honger (starvation): Situatie waarin één of meerdere goroutines geen toegang kunnen krijgen tot een gedeelde resource omdat deze constant wordt vastgehouden door anderen. In Go mutexen wordt honger niet gegarandeerd.
- Gebruik van
sync.RWMutexvoor lezen/schrijven: Als de meeste operaties lezen zijn en schrijven zeldzaam, kansync.RWMutexefficiënter zijn. Het staat meerdere goroutines toe om gelijktijdig te lezen, maar blokkeert tijdens een schrijfactie. - Kortdurende blokkades: Probeer blokkades zo kort mogelijk te houden. Hoe langer een mutex geblokkeerd is, hoe meer goroutines wachten, wat de paralleliteit vermindert.
- Raceconditie testen: Gebruik de vlag
-racebij het compileren en uitvoeren van tests (go test -race) om racecondities te detecteren, vaak veroorzaakt door verkeerd gebruik van mutexen.
Voorbeeld van gebruik van defer:
import (
"sync"
)
type SafeCounter struct {
mu sync.Mutex
v map[string]int
}
// Inc verhoogt veilig de teller voor een gegeven sleutel.
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
// Vrijgeven bij het verlaten van de functie.
defer c.mu.Unlock()
c.v[key]++
}
// Value geeft de huidige waarde van de teller voor een gegeven sleutel.
func (c *SafeCounter) Value(key string) int {
c.mu.Lock()
// Vrijgeven na het verkrijgen van de waarde.
defer c.mu.Unlock()
return c.v[key]
}