How is runtime organized in Go?
sobes.tech AI
Answer from AI
Runtime Go consists of the following key components: scheduler, garbage collector, and goroutine system.
-
Scheduler: Implements user-space threading. It maps M (many) user goroutines to N (few) OS threads. Uses an M:N model, which is more efficient than 1:1 (each goroutine is a separate OS thread) or N:1 (all goroutines share one OS thread). The scheduler manages three queues:
- Global run queue: goroutines not yet assigned to P.
- Local run queue: goroutines assigned to a specific P.
- Wait queue: goroutines blocked due to external reasons (network, file I/O).
The scheduler model is based on P (processor) - a logical processor linking G (goroutine) and M (OS thread). M executes G's code, while P provides resources and context for execution (local goroutine queue, cache). The scheduler distributes goroutines among available M and P.
-
Garbage Collector (GC): Go uses a concurrent and parallel garbage collector. It works concurrently with user code (minimized stop-the-world phases) and in parallel (using multiple CPU cores). It employs a Mark-and-Sweep algorithm with a tri-color scheme.
Object finalization is also handled by the runtime.
-
Goroutines: Lightweight, concurrent functions managed by the Go runtime, not the OS. They require less memory (initially 2KB stack, which can grow) and switch faster than OS threads. Created using the
gokeyword.Communication between goroutines occurs via channels, which are safe data exchange and synchronization mechanisms.
// Example of creating a goroutine go func() { // Code running in a separate goroutine }() // Example of using a channel ch := make(chan int) go func() { ch <- 1 // Sending data to the channel }() val := <-ch // Receiving data from the channel -
Input/Output System: The Go runtime uses non-blocking I/O operations and event multiplexing (e.g.,
epollon Linux,kqueueon FreeBSD/macOS,IOCPon Windows). When a goroutine blocks on I/O, the runtime detaches it from M, allowing M to run another goroutine, and when I/O completes, the scheduler reassigns M to the goroutine (possibly another). This efficiently utilizes system resources and avoids OS thread blocking. -
Call stack: Goroutines use a growing stack with a variable size, starting small and increasing dynamically as needed. This reduces memory usage compared to OS threads, which typically have a fixed (and larger) stack size.
Overall, the Go runtime is designed to ensure high performance and concurrency, managing goroutines, memory, and system resources efficiently and transparently for the developer.