דילוג לתוכן המרכזי
eLearner.app
מודול 7 · שיעור 1 מתוך 531/50 בקורס~12 min
שיעורי מודול (1/5)

Goroutines: מקביליות קלת משקל

A goroutine is a unit of concurrent execution managed by the Go runtime. You launch one with the go keyword in front of a function call:

Go
go greet("Anna")         // chiamata a funzione esistente
go func() {              // funzione anonima
    fmt.Println("hi")
}()

The go statement returns immediately: the goroutine starts in parallel and the caller keeps going.

Why they are "lightweight"

  • Initial stack ~2KB (grows dynamically, up to hundreds of MB if needed).
  • Multiplexed onto a small number of OS threads by the runtime (GOMAXPROCS).
  • Thousands/millions of goroutines are routine; with OS threads they would be impossible.

Conceptually it is "concurrent fire-and-forget", but with all the idiomatic tools to coordinate (channels, sync.WaitGroup, context).

main does not wait

Go
func main() {
    go func() { fmt.Println("ciao dalla goroutine") }()
    // main esce subito: niente garanzia che la goroutine completi
}

When main returns, the process terminates: goroutines do not get to "finish their work", they are simply killed together with the process. Explicit synchronization is required.

Synchronization: a preview

The three tools you will see in the next lessons:

Go
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
    work()
    done <- struct{}{}
}()
<-done   // attendi

// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()

// 3) context: cancellazione/timeout propagati

The "classic" closure-in-loop bug

Up to Go 1.21 this was a frequent gotcha:

Go
for i := 0; i < 3; i++ {
    go func() { fmt.Println(i) }()  // stampa "3 3 3" su versioni vecchie
}

From Go 1.22 the for variable is freshly created on each iteration, so the bug is fixed by default. In older codebases you will still see the fix pattern:

Go
for i := 0; i < 3; i++ {
    i := i           // shadow esplicito
    go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
    go func(n int) { fmt.Println(n) }(i)
}

Goroutine != OS thread

AspectGoroutineOS thread
Initial stack~2 KB1–8 MB (allocated at start)
Creationnanosecondsmicroseconds
SchedulingGo runtime (cooperative)kernel (preemptive)
Practical count100K+a few thousand

A single OS thread can host many goroutines. The runtime moves goroutines across threads when needed.

Try it

פעילות גופנית#go.m7.l1.e1
ניסיונות: 0טוען...

Launch the greet function as a goroutine and wait 100ms with time.Sleep before exiting main.

טוען עורך...
הצג רמז

`go` in front of a function call launches the goroutine.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#go.m7.l1.e2
ניסיונות: 0טוען...

Launch an anonymous function as a goroutine that prints 'hi'.

טוען עורך...
הצג רמז

An anonymous function is called with a trailing `()`: `go func(){...}()`.

הפתרון זמין לאחר 3 ניסיונות

Quiz#go.m7.l1.e3
מוכן

What happens if `main` exits before a goroutine completes?

Go
func main() {
  go work()
  // main ritorna immediatamente
}
אפשרויות תשובה

Recap

  • go f() launches f() concurrently; it returns immediately.
  • Goroutine = ~2 KB initial, multiplexed onto a few OS threads.
  • main does not wait: you need synchronization (channel/WaitGroup/context).
  • time.Sleep is only didactic, never for sync in production.
  • From Go 1.22 the for variable is "fresh" on each iteration (no more "3 3 3" bug).