compare Goroutine Vs Thread with an alternative
Fast recall
Quick revision
Core answer
Practical understanding of Goroutine Vs Thread.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
The rule is absolute: when the main goroutine returns from main, the program exits. Every other goroutine — mid-computation, mid-send, holding a half-written file — is simply gone. No cleanup, no cancellation callback, no final chance. The runtime doesn't attempt a shutdown handshake; it terminates.
That's why 'does main wait for goroutines?' is the wrong question — it doesn't, and by design: most programs have goroutines that may never finish (servers, listeners, pollers); waiting for them all would mean most programs never exit. Exit is main's decision, made when main's work is done.
The discipline that follows: any goroutine whose WORK matters to the outcome must be joined before main returns:
var wg sync.WaitGroup
for _, task := range tasks {
wg.Add(1)
go func(t Task) { defer wg.Done(); run(t) }(task)
}
wg.Wait() // main blocks here — the results existor the channel form — receive the results you need:
results := make(chan Result, len(tasks))
// ... goroutines send into results ...
for i := 0; i < len(tasks); i++ {
use(<-results) // main consumes until it has everything
}The bug to recognize: fire-and-forget goroutines doing necessary work (logging, flushing, writing) — the program looks correct in tests (fast goroutines finish before main) and intermittently loses output in production (main races them). If the work matters, main must wait for it; if main needn't wait, the work didn't matter.
compare Goroutine Vs Thread with an alternative
Direct Answer
main returning ends the program — immediately, all goroutines, no defers elsewhere run, no 'wait for children'. Any goroutine still needed must be joined (WaitGroup/channel) before main exits.
Deep Dive & Architecture
Why doesn't Go wait for goroutines at exit? Because 'wait for all' is undefined for real programs: servers have listener goroutines that never end, background pollers, caches. If main waited for every goroutine, most programs would never terminate — exit would require every goroutine to choose to finish. The design puts the exit decision where the structure is knowable: main, the goroutine that started everything, returns when ITS work is done.
What actually happens at the machine level: main returns → the runtime calls exit → the OS tears down the process — every thread, every goroutine's stack, in-flight writes, everything — in one process-level operation. There's no per-goroutine cleanup because the goroutines aren't independent processes; they're all one process's memory. The exit is atomic from the program's perspective.
The two sided exit story (the disciplined version):
- If the goroutine's work matters to the program's result: main joins it — WaitGroup.Wait() or a result channel — before returning. The program is correct by construction: exit happens after the needed work.
- If the goroutine's work must stop before exit: cancellation — the goroutine selects on ctx.Done() and returns; main cancels, waits (or sleeps grace-period), exits. Servers do this in Shutdown: stop accepting, cancel handlers, wait briefly, exit.
The failure shape in production: fire-and-forget goroutines writing output (log flusher, async writer). Tests are fast → goroutines win the race and finish → everything looks fine. Under load, main finishes its path while the writer is mid-write → process exits mid-flush → truncated logs, corrupted writes, at exactly the worst time (high load). The fix is never a sleep; it's making the join explicit — the goroutine's work was needed, so main waits for it.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Goroutine Vs Thread, and when would you use it?
- When would you use Goroutine Vs Thread in a real project?
- What is a common mistake when using Goroutine Vs Thread?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.