ProgrammatieBackend ontwikkelaar

Welke soorten synchronisatie bestaan er in Go? Hoe sync.Mutex, sync.RWMutex en sync.WaitGroup te gebruiken, en wat zijn de nuances van elk geval?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

In Go worden structuren uit het sync-pakket gebruikt voor de synchronisatie van concurrerende goroutines, de meest voorkomende zijn sync.Mutex, sync.RWMutex en sync.WaitGroup.

sync.Mutex biedt mechanismen voor wederzijds uitsluiting bij toegang tot gedeelde gegevens. Zijn methoden zijn Lock() (vergrendelt) en Unlock() (ontgrendelt).

sync.RWMutex breidt de mogelijkheden van een gewone mutex uit: het staat gelijktijdig lezen toe, maar exclusieve wijziging.

sync.WaitGroup is bedoeld voor het wachten op de voltooiing van een groep goroutines. Met Add(int), Done() en Wait() beheert u de levenscyclus van parallel werk.

Bijvoorbeeld:

var mu sync.RWMutex data := 0 // Lezen mu.RLock() fmt.Println(data) mu.RUnlock() // Schrijven mu.Lock() data = 42 mu.Unlock()

Nuances:

  • Gebruik altijd Unlock in een defer-blok om te voorkomen dat u vergeet de mutex te ontgrendelen, zelfs bij paniek.
  • Zorg ervoor dat het aantal aanroepen van WaitGroup.Done() overeenkomt met Add().
  • Kopieer geen WaitGroup, Mutex en RWMutex!

Vraag met een valstrik

Kan dezelfde sync.Mutex (of RWMutex) twee keer achter elkaar in dezelfde goroutine worden vastgelegd? Wat gebeurt er?

Antwoord: Nee, als u Lock() op dezelfde Mutex twee keer achter elkaar aanroept zonder tussenliggende Unlock(), zal de goroutine voor altijd vergrendeld zijn (deadlock). In Go zijn mutexen niet-recursief.

Voorbeeld:

var mu sync.Mutex mu.Lock() // ... mu.Lock() // DEADLOCK: zal voor altijd vergrendeld zijn, omdat dezelfde thread de lock al vasthoudt

Voorbeelden van echte fouten


Verhaal

In een project voor een high-load REST API wikkelde de ontwikkelaar de hele verwerking van de aanvraag in één mutex. Dit veroorzaakte een scherpe daling van de prestaties - slechts één aanvraag kon tegelijkertijd worden verwerkt, terwijl er duizenden klanten bedoeld waren te worden bediend. De oorzaak was onwetendheid over het verschil tussen Mutex en RWMutex en het negeren van gelijktijdig lezen.


Verhaal

Bij het kopiëren van een structuur met Mutex erin, gaf een van de teamleden per ongeluk een kopie door aan een andere functie. Dit leidde tot een paniekbericht "sync: copy of sync.Mutex" en crashes in producties onder hoge belasting.


Verhaal

Bij het gebruik van WaitGroup vergat men Done() in verschillende goroutines aan te roepen, wat leidde tot een eeuwige wachttijd op Wait(), waardoor de hoofdthread werd geblokkeerd. Hierdoor verloor de service de beschikbaarheid tot handmatige herstart.