Introduction
A goroutine is a lightweight, independently executing function managed by the Go runtime. Goroutines are Go’s built-in way of handling concurrency, allowing functions to run asynchronously and enabling many tasks to execute seemingly at the same time.
What is a Goroutine?
A goroutine is a function that runs concurrently with other goroutines in the same program.
- They are much cheaper than operating system threads.
- We create them by prefixing a function call with the
go
keyword. - Once started, a goroutine is scheduled and managed by the Go runtime, not by the operating system.
Example:
package main
import (
"fmt"
"time"
)
func sayHello() {
fmt.Println("Hello from goroutine!")
}
func main() {
go sayHello() // start goroutine
fmt.Println("Hello from main!")
time.Sleep(time.Second) // allow goroutine to finish
}
Why Goroutines Exist
Before goroutines, developers often had to manage OS threads directly, which is:
- Resource-heavy
- Complex to coordinate
- Difficult to scale to thousands or millions of concurrent tasks
Goroutines solve this by being:
- Lightweight (few KB initial stack, grows dynamically)
- Cheap to create (can have millions in a program)
- Scheduled in user space (no costly kernel context switches for every scheduling decision)
How Goroutines Work Under the Hood
Go uses its own scheduler to manage goroutines efficiently. This is based on the G–M–P model:
- G: Goroutine (the task)
- M: Machine (OS thread running goroutines)
- P: Processor (manages the execution context and run queue)
The scheduler maps many goroutines (G
) to a limited number of OS threads (M
) through processors (P
).
By default, the number of processors is equal to the number of CPU cores (GOMAXPROCS
).
Lifecycle of a Goroutine
- Creation — Starts when we call a function with the
go
keyword. - Execution — Runs independently, sharing the program’s memory space with other goroutines.
- Termination — Ends when the function returns.
- Program Exit — If
main()
finishes, all goroutines are stopped immediately.
Key Characteristics
- Extremely lightweight compared to threads
- Not tied to any specific OS thread
- Managed by Go runtime, not the OS directly
- Stacks grow and shrink as needed
- Can run millions in one program without exhausting resources