intermediate
Step 9 of 15
Goroutines and Concurrency
Go Programming
Goroutines and Concurrency
Concurrency is one of Go's defining features. Goroutines are lightweight threads managed by the Go runtime that enable you to run thousands — even millions — of concurrent tasks efficiently. Unlike OS threads that consume megabytes of memory each, goroutines start with just a few kilobytes of stack space that grows as needed. Launching a goroutine is as simple as adding the go keyword before a function call. This makes concurrent programming in Go accessible and practical for everyday tasks like handling multiple HTTP requests, processing data pipelines, or performing I/O operations in parallel.
Goroutines
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait() // Wait for all goroutines to finish
fmt.Println("All workers completed")
}
Mutex for Shared State
type SafeCounter struct {
mu sync.Mutex
count map[string]int
}
func (c *SafeCounter) Increment(key string) {
c.mu.Lock()
defer c.mu.Unlock()
c.count[key]++
}
func (c *SafeCounter) Get(key string) int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count[key]
}
Pro tip: Usesync.WaitGroupto wait for a group of goroutines to finish, andsync.Mutexto protect shared state. Prefer channels over mutexes when possible — Go's motto is "Do not communicate by sharing memory; share memory by communicating."
Key Takeaways
- Goroutines are lightweight concurrent functions launched with the
gokeyword. - Use
sync.WaitGroupto coordinate goroutine completion. - Use
sync.Mutexto protect shared data from race conditions. - Go can handle millions of goroutines efficiently with minimal memory overhead.
- Run
go run -race main.goto detect data races during development.