Do many things at once
A web server answers thousands of requests at once; a crawler fetches hundreds of pages while parsing others. Go makes this cheap: put go in front of a function call and it runs concurrently in a goroutine — a lightweight thread that starts with a stack of a few kilobytes, so a program can run hundreds of thousands of them.
Go's model comes from Tony Hoare's 1978 paper *Communicating Sequential Processes*: independent processes that share nothing and talk over channels. The Go proverb is "Don't communicate by sharing memory; share memory by communicating." Concurrency is also where the trickiest Go bugs live — chapters 8 and 9 of *100 Go Mistakes* cover them.
Honest note about this simulator: goroutines really run concurrently here, but taking turns on one thread in a fixed order, switching only when one blocks (on a channel, a lock, a WaitGroup or time.Sleep). Real Go runs them in parallel on all your cores, in an unpredictable order. So code that's correct here is correct in Go, but a data race — two goroutines touching the same variable without synchronisation — can't show its random wrong answers here. Real Go finds races with go test -race (mistake #83).
Channels
A channel passes values between goroutines: ch := make(chan int). ch <- v sends; v := <-ch receives. On an unbuffered channel a send waits until another goroutine receives — the two meet, which synchronises them. A buffered channel, make(chan int, 3), lets senders run ahead until the buffer is full.
package main
import "fmt"
func squares(n int, out chan<- int) {
for i := 1; i <= n; i++ {
out <- i * i
}
close(out)
}
func main() {
ch := make(chan int)
go squares(4, ch)
for v := range ch {
fmt.Print(v, " ")
}
fmt.Println()
v, ok := <-ch
fmt.Println(v, ok)
}- Only the sender closes a channel, once. Sending on a closed channel panics.
- Without close, range ch waits forever once the values stop.
- When main returns the program ends — even if other goroutines are still working. Wait for them.