Goroutines și canalele Go activează un set bine stabilit de modele de concurență care rezolvă probleme obișnuite — distribuirea muncii, fan-out/fan-in, pipelines și rate limiting. Cunoașterea acestor modele idiomatice te permite să construiești sisteme concurente corecte și eficiente.
Worker pool — bounded concurrency
func workerPool(jobs <-chan int, results chan<- int, numWorkers int) {
var wg sync.WaitGroup
for w := 0; w < numWorkers; w++ { // a FIXED number of workers
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs { // each worker pulls jobs until the channel closes
results <- process(job)
}
}()
}
wg.Wait()
close(results)
}
Un worker pool rulează un număr fix de goroutine care consumă dintr-un canal jobs partajat — limitând concurența (de exemplu, nu deschide 10.000 conexiuni BD; folosește 10 workers). Acesta este modelul cel mai important pentru controlarea utilizării resurselor.
Fan-out / fan-in
Fan-out: distribute work across MULTIPLE goroutines (parallelize)
Fan-in: MERGE results from multiple goroutines back into one channel
// fan-in: merge several channels into one
func merge(channels ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, ch := range channels {
wg.Add(1)
go func(c <-chan int) {
defer wg.Done()
for v := range c { out <- v } // forward each channel's values to out
}(ch)
}
go func() { wg.Wait(); close(out) }() // close out when all sources are drained
return out
}
Pipeline — stages connected by channels
// each stage is a goroutine: receives from an input channel, sends to an output channel
func generate(nums ...int) <-chan int {
out := make(chan int)
go func() { for _, n := range nums { out <- n }; close(out) }()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() { for n := range in { out <- n * n }; close(out) }()
return out
}
// compose: square(generate(1,2,3)) → a streaming pipeline
for result := range square(generate(1, 2, 3)) { fmt.Println(result) }
Un pipeline conectează etape de procesare prin canale — datele curg, fiecare etapă le transformă concurent.
Rate limiting
limiter := time.Tick(200 * time.Millisecond) // a tick every 200ms
for req := range requests {
<-limiter // wait for the next tick before proceeding
go handle(req) // → at most 5 requests/second
}
Cancellation with context (cross-cutting)
select {
case result := <-work:
case <-ctx.Done(): return // stop on cancellation — prevents leaks
}
De ce conteaza
Aceste modele de concurență sunt setul de instrumente practic pentru construirea sistemelor Go concurente reale, transformând goroutine brute și canale în soluții structurate și corecte pentru probleme recurente.
Worker pool-ul este deosebit de important — limitează concurența pentru a proteja resursele limitate (conexiunile bazei de date, limitele ratei API, memoria), prevenind eroarea obișnuită de a genera goroutines nelimitate care epuizează sistemul. Fan-out/fan-in paralelizează munca și fuzionează rezultatele; pipelines modelează transformările datelor de streaming în mod curat; rate limiting controlează debitul.
Combinate cu anularea bazată pe context (pentru a evita scurgerile de goroutine), aceste modele sunt modul în care serviciile Go în producție gestionează concurența în siguranță și eficient.
Înțelegerea lor — și în special știind cum să limitezi concurența cu worker pools în loc să lansezi goroutines nelimitate — este o marcă a competenței senioare în Go și un subiect frecvent de interviu avansat, deoarece concurența naivă (goroutines nelimitate, scurgeri, race-uri) este o sursă comună de eșecuri în producție.
