Crash Courses · Masters
Goroutines & Channels
Lightweight concurrency, communication, and synchronization
40 min read+180 XP on completionCert: Go Crash Course
Tap any word in the text below to start reading from there.
Goroutines & Channels
Launching a Goroutine
package main
import (
"fmt"
"time"
)
func sayHello(name string) {
fmt.Printf("Hello, %s!\n", name)
}
func main() {
go sayHello("Alice") // runs concurrently
go sayHello("Bob")
time.Sleep(100 * time.Millisecond) // crude sync — don't do this in production
}Channels
Channels replace shared memory. Send with <- and receive with <-:
ch := make(chan int) // unbuffered
go func() {
ch <- 42 // send (blocks until receiver is ready)
}()
v := <-ch // receive (blocks until sender sends)
fmt.Println(v) // 42WaitGroup (production sync)
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // decrement counter when done
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait() // blocks until all Done() calls are made
fmt.Println("All workers finished")
}Buffered Channels
ch := make(chan string, 3) // buffer of 3
ch <- "a" // does not block
ch <- "b"
ch <- "c"
// ch <- "d" // would block — buffer full
fmt.Println(<-ch) // a
fmt.Println(<-ch) // bselect Statement
func main() {
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch1 <- "one"
ch2 <- "two"
select {
case msg := <-ch1:
fmt.Println("Received from ch1:", msg)
case msg := <-ch2:
fmt.Println("Received from ch2:", msg)
}
}Mutex for Shared State
When goroutines share mutable state, protect it with a mutex:
type SafeCounter struct {
mu sync.Mutex
v map[string]int
}
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
c.v[key]++
c.mu.Unlock()
}Closing Channels & Range
ch := make(chan int, 5)
for i := 0; i < 5; i++ { ch <- i }
close(ch)
for v := range ch { // loops until channel is closed
fmt.Println(v)
}Reading progress
0% read
In this module
goroutine
channel
buffered channel
select
0%