sync.WaitGroup.Go în Go

Pornește funcția f într-un goroutine nou și o adaugă în WaitGroup; înlocuiește perechea Add(1) + defer Done().

Sintaxă
func (wg *WaitGroup) Go(f func())

Ce face sync.WaitGroup.Go

wg.Go(f) face trei lucruri deodată: wg.Add(1), pornește f cu go și apelează wg.Done() când f se termină. Codul devine mai scurt și nu mai poți uita Add sau Done.

Funcția f nu primește argumente și nu returnează nimic; datele le iei din variabilele din jur (închidere). Din Go 1.22 fiecare iterație a buclei for are variabilele ei, deci i și f din buclă pot fi folosite direct. Documentația cere ca f să nu se oprească cu panică.

Parametri

Parametru Descriere
f Funcția de rulat în goroutine-ul nou, de forma func().

Ce returnează

Nimic.

Exemple

Exemplul 1: Verificarea mai multor site-uri

package main

import (
	"fmt"
	"sync"
	"time"
)

func verifica(site string) string {
	time.Sleep(10 * time.Millisecond)
	if site == "vechi.example" {
		return "nu răspunde"
	}
	return "ok"
}

func main() {
	site := []string{"dexblog.ro", "vechi.example", "go.dev"}
	stare := make([]string, len(site))

	var wg sync.WaitGroup
	for i, s := range site {
		wg.Go(func() {
			stare[i] = verifica(s)
		})
	}
	wg.Wait()

	for i, s := range site {
		fmt.Printf("%-14s %s\n", s, stare[i])
	}
}

Rezultat

dexblog.ro     ok
vechi.example  nu răspunde
go.dev         ok

Exemplul 2: Go împreună cu un mutex

Numărăm cuvintele din mai multe texte în paralel într-un singur map, protejat de mutex.

package main

import (
	"fmt"
	"strings"
	"sync"
)

func main() {
	texte := []string{
		"ana are mere",
		"mere și pere la piață",
		"ana vinde pere",
	}
	var (
		wg       sync.WaitGroup
		mu       sync.Mutex
		frecvente = map[string]int{}
	)
	for _, t := range texte {
		wg.Go(func() {
			for _, cuv := range strings.Fields(t) {
				mu.Lock()
				frecvente[cuv]++
				mu.Unlock()
			}
		})
	}
	wg.Wait()
	fmt.Println(frecvente)
}

Rezultat

map[ana:2 are:1 la:1 mere:2 pere:2 piață:1 vinde:1 și:1]

Greșeli frecvente

  • Scrii wg.Go(lucru(x)): asta apelează lucru imediat, în goroutine-ul curent. Scrie wg.Go(func() { lucru(x) }).
  • Combini wg.Go cu wg.Add(1) sau defer wg.Done() pentru aceeași sarcină; contorul se strică. Go le face singur.

Comenzi înrudite

  • sync.WaitGroup: Așteaptă ca un grup de goroutine să termine: Add mărește contorul, Done îl scade, Wait blochează până ajunge la zero.
  • sync.Mutex: Lacăt de excludere reciprocă: doar un goroutine pe rând poate rula codul dintre Lock() și Unlock().