Each test is 5 questions with varying difficulty.
AI Prep covers AI Agents, Generative AI, ML Fundamentals, NLP & LLMs and a lot more, with adaptive tests and daily challenges. Fully offline on Android. Free to try, one-time unlock for lifetime access.
Goroutines are the fundamental unit of concurrency in Go, representing lightweight, independently executing functions managed by the Go runtime rather than the operating system. In 2026, as high-throughput microservices and distributed AI inference pipelines become standard, mastering goroutines is essential for any Go developer. Interviewers focus on this topic to assess a candidate's ability to write non-blocking, memory-efficient code that avoids common pitfalls like data races and resource exhaustion. Junior candidates are expected to understand basic spawning and channel communication, while senior engineers must demonstrate deep knowledge of the M:N scheduler, stack growth mechanisms, and strategies for preventing goroutine leaks in complex, long-running production systems.
Goroutines are the engine behind Go's ability to handle tens of thousands of concurrent connections on a single machine. Unlike OS threads, which typically consume 1-2MB of stack space, goroutines start with a tiny 2KB stack that grows and shrinks dynamically. This efficiency is critical for modern systemsβsuch as high-frequency trading platforms or real-time AI API gatewaysβwhere thread-per-request models would collapse under memory pressure. In an interview, the ability to discuss goroutines reveals whether a candidate understands the trade-offs between concurrency and parallelism, the cost of context switching, and the importance of lifecycle management. A strong answer demonstrates awareness of the Go scheduler's 'work-stealing' algorithm and the dangers of unbounded goroutine creation, which can lead to memory leaks and catastrophic system failure. Conversely, a weak answer often treats goroutines as 'cheap threads' without considering the underlying runtime overhead or the necessity of proper termination patterns.
The Go runtime uses a G-P-M model: G (Goroutine), P (Processor), and M (Machine/OS Thread). The P represents the resource required to execute Go code, while M is the actual OS thread. Gs are queued on Ps. If a G makes a blocking syscall, the M is detached from the P, and a new M is attached to the P to continue executing other Gs.
Goroutines are created and placed in a Local Run Queue. The P executes Gs from the queue. If the queue is empty, the P attempts to steal from other Ps or the Global Run Queue.
[Global Queue]
β
[P1] β [P2] β [P3]
β β β
[M1] [M2] [M3]
β β β
[G1] [G2] [G3]
β β β
[CPU Core 1-N]
Limiting concurrent tasks by spawning a fixed number of goroutines reading from a shared channel.
Trade-offs: Prevents resource exhaustion but adds complexity in error handling.
Passing context.Context to child goroutines to enable cancellation and timeout propagation.
Trade-offs: Standardizes termination but requires passing context through all layers.
Spawning multiple goroutines (fan-out) and merging their results into a single channel (fan-in).
Trade-offs: Increases throughput but requires careful channel closing logic.
| Reliability | Use context timeouts and circuit breakers to prevent cascading failures in goroutine chains. |
| Scalability | Horizontal scaling is easier when goroutines are managed via worker pools to keep memory usage predictable. |
| Performance | Monitor goroutine counts via runtime.NumGoroutine() to detect spikes; avoid excessive channel contention. |
| Cost | Efficient goroutine usage reduces memory footprint, allowing higher density on smaller cloud instances. |
| Security | Prevent malicious input from triggering unbounded goroutine creation (DoS risk). |
| Monitoring | Track goroutine count, block duration, and scheduler latency in Prometheus. |
No. Goroutines are user-space threads managed by the Go runtime. They are much lighter (starting at 2KB) and are multiplexed onto a smaller number of OS threads by the scheduler, whereas OS threads are managed by the kernel and have much larger, fixed stack sizes.
You can spawn millions of goroutines, as they are very memory-efficient. However, the practical limit is dictated by your system's available memory and the resources your goroutines consume. Unbounded spawning without a strategy will eventually lead to an OOM crash.
Concurrency is the ability to structure a program to handle multiple tasks at once (e.g., using goroutines to manage I/O). Parallelism is the simultaneous execution of multiple tasks on different CPU cores. Go's scheduler provides both by mapping goroutines to OS threads.
A goroutine leak occurs when a goroutine is blocked indefinitely (e.g., waiting on a channel that will never be sent to) and cannot be garbage collected. This consumes memory and resources, eventually leading to system instability.
The M:N scheduler allows Go to handle massive concurrency without the overhead of context-switching between thousands of OS threads. It maps M goroutines to N OS threads, allowing the runtime to optimize execution based on the workload and available CPU cores.
You can use the 'pprof' tool to inspect the goroutine profile. If you see a high number of goroutines in a 'waiting' or 'blocked' state that does not decrease over time, you likely have a leak. Monitoring 'runtime.NumGoroutine()' is also a good practice.
No, you cannot manually set the stack size of an individual goroutine. The Go runtime manages stack size dynamically, starting small and growing/shrinking as needed. This is a core feature that makes goroutines so efficient.
GOMAXPROCS limits the number of OS threads that can execute user-level Go code simultaneously. By default, it is set to the number of available CPU cores. Adjusting it can affect performance for compute-bound tasks.
No, Go does not have a GIL. It is designed for true multi-threaded execution, allowing goroutines to run in parallel on multiple CPU cores without the performance bottlenecks associated with a GIL.
The idiomatic way to share data in Go is to use channels ('Do not communicate by sharing memory; instead, share memory by communicating'). For performance-critical sections, you can use 'sync.Mutex' or 'sync.RWMutex' to protect shared state.
AI Prep covers AI Agents, Generative AI, ML Fundamentals, NLP & LLMs and a lot more, with adaptive tests and daily challenges. Fully offline on Android. Free to try, one-time unlock for lifetime access.