Description
A Goroutine is a lightweight, independently executing function managed by the Go runtime. It is the fundamental unit of concurrency in the Go programming language (Golang) and allows developers to run multiple tasks simultaneously, without the complexity of manual thread management.
Unlike traditional threads, goroutines are cheap to create, share the same address space, and are scheduled cooperatively by the Go runtime using a user-space scheduler.
Key Features
| Feature | Description |
|---|---|
| Lightweight Threads | Thousands of goroutines can be run simultaneously with minimal overhead |
| Automatic Scheduling | Go runtime schedules goroutines, not the OS kernel |
| Shared Memory Model | Communicate via channels, but variables exist in the same space |
| Non-blocking I/O | Efficient use of system resources during network or file operations |
| Easy Syntax | Use go keyword to launch functions concurrently |
Basic Syntax
func sayHello() {
fmt.Println("Hello!")
}
func main() {
go sayHello() // Executes in a separate goroutine
time.Sleep(time.Second)
}
How It Works
gokeyword launches a goroutine.- The function executes independently from the main goroutine.
- The Go scheduler maps goroutines onto a small pool of OS threads.
- Goroutines yield execution voluntarily during I/O or channel operations.
- Scheduler resumes them later using a cooperative scheduling model.
Real-Life Analogy
Imagine you’re organizing a group project. Instead of asking one person to do everything in order, you assign different people (goroutines) to handle specific parts in parallel. They work independently and report back via a shared board (channel).
Goroutines vs Threads
| Feature | Goroutine | Thread |
|---|---|---|
| Memory | ~2KB stack, grows dynamically | ~1MB stack per thread |
| Startup Cost | Extremely low | Relatively high |
| Count | Can create millions | Usually limited to thousands |
| Scheduling | Managed by Go runtime | Managed by OS kernel |
| Communication | Uses channels | Uses shared memory + synchronization |
Channels: Communicating Between Goroutines
func worker(ch chan string) {
ch <- "work done"
}
func main() {
ch := make(chan string)
go worker(ch)
fmt.Println(<-ch)
}
Channels are typed pipes that connect concurrent goroutines.
Go Scheduler Model (M:N Scheduler)
Go uses an M:N scheduling model:
- M = Number of OS threads
- N = Number of goroutines
- G = Goroutine structure
- P = Processor context to execute goroutines
The scheduler maps many goroutines (G) to a smaller number of threads (M) using a number of logical processors (P).
Advanced Topics
Buffered Channels
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
Buffered channels allow storing data without immediate receiving.
Select Statement
Allows waiting on multiple channels:
select {
case msg := <-ch1:
fmt.Println(msg)
case msg := <-ch2:
fmt.Println(msg)
default:
fmt.Println("no activity")
}
Goroutine Leak
Occurs when a goroutine is waiting on a channel that never sends data, causing a memory leak. Always ensure cleanup or use context cancellation.
Common Pitfalls
| Pitfall | Solution |
|---|---|
Missing go keyword | Only launches concurrently if prefixed with go |
| Data Race | Use channels or mutexes to avoid race conditions |
| Deadlocks | Always pair sends and receives, or use buffered channels |
| Goroutine Leak | Use context.Context for lifecycle control |
| Blocking Main | Ensure main goroutine waits (via WaitGroup, sleep, etc.) |
Code Patterns
Launching Multiple Goroutines
for i := 0; i < 5; i++ {
go func(n int) {
fmt.Println(n)
}(i)
}
Use function arguments to avoid variable capture issues.
WaitGroup for Synchronization
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("done")
}()
wg.Wait()
Ensures main goroutine waits for others to finish.
Using context for Cancellation
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
// do work
}
}
}(ctx)
cancel() // signal cancellation
Performance and Scalability
Goroutines make Go extremely efficient for:
- Network servers (e.g., thousands of concurrent connections)
- Real-time applications
- Parallel computations
- Pipelines and stream processing
Tools for Debugging Goroutines
| Tool | Purpose |
|---|---|
go run -race | Detects data races |
pprof | Profiles goroutines and memory |
runtime.NumGoroutine() | Returns active goroutine count |
Related Concepts
| Concept | Relationship |
|---|---|
| Channel | Primary way to communicate between goroutines |
| WaitGroup | Synchronizes completion of multiple goroutines |
| Mutex | Protects shared memory (alternative to channels) |
| Task | Similar abstraction in .NET and Python |
| Coroutine | Goroutines are a form of coroutine |
| Scheduler | Determines execution order of goroutines |
Related Keywords
- Channel
- Concurrency
- Cooperative Scheduling
- Goroutine Leak
- M:N Scheduler
- Mutex
- Race Condition
- Runtime Scheduler
- WaitGroup
- Yield Point









