Goroutines and channels

Run functions concurrently with go, wait with sync.WaitGroup, and pass results over a channel.

Runs in Zerethon IDE · Go 1.27 Official Go documentation ↗
main.go
package main

import (
	"fmt"
	"sync"
)

func square(n int, results chan<- int, wg *sync.WaitGroup) {
	defer wg.Done()
	results <- n * n
}

func main() {
	results := make(chan int, 5)
	var wg sync.WaitGroup
	for n := 1; n <= 5; n++ {
		wg.Add(1)
		go square(n, results, &wg)
	}
	wg.Wait()
	close(results)

	sum := 0
	for r := range results {
		sum += r
	}
	fmt.Println("sum of squares:", sum)
}

Output

sum of squares: 55
  • go f() starts f and returns immediately. When main returns, the program ends — even if goroutines are still running.
  • Goroutines finish in any order. Here the sum is the same every time, but printing from each goroutine would not be.
  • defer runs a call when the surrounding function returns; defer wg.Done() cannot be forgotten on an early return.
  • Reading from a channel nobody will ever write to stops the program with fatal error: all goroutines are asleep - deadlock!.

Tip: A run has half a CPU and a small process limit: a few goroutines are fine, thousands of busy ones only make the run slower.