Go by Example: Goroutines
Dive into Concurrency with Goroutines, Go's lightweight threads. This example demonstrates how to launch concurrent functions using the `go` keyword, explaining their non-blocking nature and how the Go runtime schedules them efficiently.
Code
package main
import (
"fmt"
"time"
)
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
// Synchronous call
f("direct")
// Goroutine call
go f("goroutine")
// Anonymous function goroutine
go func(msg string) {
fmt.Println(msg)
}("going")
// Wait for goroutines to finish
time.Sleep(time.Second)
fmt.Println("done")
}Explanation
Goroutines are the cornerstone of Go's concurrency model, representing lightweight threads of execution managed entirely by the Go runtime rather than the operating system. Unlike OS threads that typically consume 1-8MB of stack space, goroutines start with a tiny 2KB stack that can grow and shrink dynamically as needed. This efficiency allows a single Go program to run thousands or even millions of concurrent goroutines without exhausting system resources.
Creating a goroutine is remarkably simple—just prefix any function call with the go keyword. This launches the function execution concurrently with the calling code, and control returns immediately to the caller without waiting for the function to complete. The Go runtime employs a sophisticated M:N scheduler that multiplexes many goroutines onto a smaller number of OS threads, using techniques like work-stealing to balance load and cooperative scheduling to handle blocking operations efficiently.
Key characteristics of goroutines:
- Extremely lightweight (2KB initial stack vs 1-8MB for OS threads)
- Managed by Go runtime's efficient scheduler, not the OS
- Fast creation and context-switching compared to OS threads
- Communicate via channels following CSP (Communicating Sequential Processes) model
- If main() exits, all goroutines terminate immediately

