Sikau

Go · Day 8 · about 45 min

Goroutines and channels

go, channels, select, WaitGroup, Mutex — and deadlocks.

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.

The rest of this lesson

  • Waiting, locking and selectexplain
  • Deadlockexplain
  • Buffered channelspredict
  • Concurrency toolsmatch
  • Fan infill
  • Work in parallelwrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 10 lessons of Go