Go is oorspronkelijk ontworpen voor het schrijven van hoogpresterende netwerk- en parallelle programma's, daarom is er speciale aandacht besteed aan de ingebouwde scheduler en eenvoudig beheer van parallelisme met behulp van goroutines. In tegenstelling tot de meeste talen, waar OS-threads direct door de programmeertaal worden beheerd, zijn goroutines in Go lichter, duizenden kunnen gelijktijdig draaien bovenop een vast aantal systeemthreads.
Probleem: direct beheer van threads is ingewikkeld: dit leidt tot snelle uitputting van middelen, data races en moeilijkheden bij het beheer van geheugen.
Oplossing: Go gebruikt het M:N-model — een groot aantal goroutines (M) wordt gemultiplexed over een beperkt aantal OS-threads (N). Dit wordt beheerd door de scheduler, die is geïmplementeerd op het niveau van de Go-runtime, die automatisch de uitvoering van goroutines balanceert en herverdeelt. De programmeur beheert alleen de opstart en synchronisatie van goroutines, niet de OS-threads direct.
Voorbeeldcode:
package main import ( "fmt" "time" ) func worker(id int) { fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) } func main() { for i := 0; i < 5; i++ { go worker(i) } time.Sleep(2 * time.Second) }
Belangrijke kenmerken:
Zal elke goroutine concurrerend uitgevoerd worden op een afzonderlijke processor kern?
Nee. Goroutines worden gemultiplexed en de scheduler bepaalt het daadwerkelijke aantal gelijktijdig uitgevoerde taken.
Kun je handmatig de uitvoering van specifieke goroutines/threads beheren?
Nee. De Go-runtime biedt geen interface voor directe planning. Uitzondering is GOMAXPROCS om het aantal OS-threads in te stellen.
Betekent een groot aantal goroutines automatische versnelling van het programma?
Nee. Een groot aantal concurrente bewerkingen kan leiden tot extra overhead: contextwisselingen, contention voor middelen, toenemende GC-tijd en geheugenverbruik.
Een microservice verwerkte gelijktijdig binnenkomende verzoeken, beperkte het aantal goroutines niet en wachtte niet op voltooiing via WaitGroup — resultaat: langere responstijden, data races, onvoorspelbare time-outs.
Voordelen:
Nadelen:
Een werkersmanager is geïmplementeerd via een pool van goroutines, het aantal tegelijkertijd werkende taken is beperkt via een semaphore of kanalen. WaitGroup wacht correct op de voltooiing van alle taken.
Voordelen:
Nadelen: