ProgrammatieBackend ontwikkelaar

Verklaar wat een goroutine is in Go. Hoe werkt het onder de motorkap en wat is het verschil met threads in andere talen?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

Een goroutine is een lichtgewicht uitvoeringsthread, beheerd door de Go-runtime. Om een nieuwe goroutine te starten, gebruik je het sleutelwoord go voor de functieaanroep. Onder de motorkap wordt er een structuur aangemaakt die de stack en de status van de taak beschrijft, die aan de wachtrij van de goroutinescheduler wordt toegevoegd.

In tegenstelling tot OS-threads heeft een goroutine een veel kleinere initiële stack (meestal 2 KB), en de stack wordt automatisch vergroot indien nodig. De Go-scheduler verdeelt ze automatisch over de beschikbare OS-threads (M:N-model).

Belangrijkste verschillen met threads:

  • Worden sneller aangemaakt en vereisen minder geheugen
  • Worden gepland door de Go-runtime en niet door het OS
  • Schalen automatisch op de beschikbare cores
  • Synchronisatie is gerealiseerd via kanalen, wat veel klassen van race-voorwaarden voorkomt

Voorbeeld van het gebruik van goroutines en kanalen:

package main import ( "fmt" "time" ) func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Printf("worker %d begon job %d\n", id, j) time.Sleep(time.Second) fmt.Printf("worker %d voltooide job %d\n", id, j) results <- j * 2 } } func main() { jobs := make(chan int, 5) results := make(chan int, 5) for w := 1; w <= 3; w++ { go worker(w, jobs, results) } for j := 1; j <= 5; j++ { jobs <- j } close(jobs) for a := 1; a <= 5; a++ { <-results } }

Trickvraag

Kunnen Go-goroutines parallel draaien op meerdere cores?

Een vaak voorkomende foutieve antwoord is: "Nee, omdat Go groene threads gebruikt." In werkelijkheid kan Go, met behulp van een omgevingsvariabele of de oproep runtime.GOMAXPROCS(n), de uitvoering van goroutines op alle beschikbare procescores paralleliseren.

Voorbeeld:

import "runtime" func main() { runtime.GOMAXPROCS(4) // Sta toe om 4 cores te gebruiken ... }

Voorbeelden van echte fouten door onbekendheid met de fijne kneepjes van het onderwerp


Verhaal

In een backend-serviceproject in Go was er een pool van workers geïmplementeerd via goroutines, maar de programmeurs vergeten het aantal gelijktijdig draaiende goroutines te beperken. Als gevolg hiervan startte de applicatie duizenden goroutines bij toenemende belasting, wat leidde tot geheugenuitputting en crash van de service. Het probleem werd opgelost door een limiet in te voeren voor actieve goroutines (bijvoorbeeld met behulp van een semaphore of worker pool).


Verhaal

Een van de medewerkers synchroniseerde gegevens tussen goroutines verkeerd door gewone globale variabelen te gebruiken zonder mutexen of kanalen. Dit veroorzaakte een race condition, waardoor er af en toe fouten optraden bij het verwerken van betalingen. Het probleem werd pas ontdekt nadat het in productie was.


Verhaal

In de parsingservice was het moment van het doorgeven van nil-kanalen in select gemist: na sluiting van het kanaal bleef select geblokkeerd wachten op gegevens, waardoor sommige goroutines "vastliepen". Dit werd verholpen door nil toe te wijzen aan het gesloten kanaal en select correct te verwerken.