Goroutines are flat from the scheduler's perspective—no parent-child hierarchy. A spawned goroutine is just another G in the queue.
func fetchAll() {
go fetch("binance") // spawns and returns immediately
go fetch("coinbase") // spawns and returns immediately
} // function exits, but goroutines may still be running!
If main() exits, all goroutines are killed—even if they're still working.
func fetchAll() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
fetch("binance")
}()
go func() {
defer wg.Done()
fetch("coinbase")
}()
wg.Wait() // blocks until both complete
}
| Method | What It Does |
|---|---|
wg.Add(n) |
Increment counter by n |
wg.Done() |
Decrement counter by 1 |
wg.Wait() |
Block until counter reaches 0 |
defer wg.Done()// ✓ Correct
go func() {
defer wg.Done() // always runs, even on panic
fetch("binance")
}()
// ✗ Wrong
go func() {
fetch("binance")
wg.Done() // skipped if fetch() panics → wg.Wait() blocks forever
}()
| Pattern | On Success | On Panic |
|---|---|---|
defer wg.Done() |
✓ Runs | ✓ Runs |
wg.Done() at end |
✓ Runs | ✗ Skipped |
Always
defer wg.Done()at the start of the goroutine, notwg.Done()at the end.
When you have goroutines spawning goroutines: each level has its own WaitGroup.
func main() {
var exchangeWg sync.WaitGroup
exchanges := []string{"binance", "coinbase", "kraken", "okx", "bybit"}
for _, exchange := range exchanges {
exchangeWg.Add(1)
go func(ex string) {
defer exchangeWg.Done()
// Each exchange has its OWN WaitGroup for endpoints
var endpointWg sync.WaitGroup
endpoints := getEndpoints(ex) // returns 2-5 endpoints
for _, endpoint := range endpoints {
endpointWg.Add(1)
go func(ep string) {
defer endpointWg.Done()
fetch(ex, ep, bus)
}(endpoint)
}
endpointWg.Wait() // exchange waits for ALL its endpoints
log.Printf("%s: all endpoints done", ex)
}(exchange)
}
exchangeWg.Wait() // main waits for ALL exchanges
log.Println("all exchanges done")
}
main()
│
├─ exchangeWg.Wait() ─────────────────────────────────────┐
│ │
├─► G: binance ──┬─ endpointWg.Wait() ──┐ │
│ ├─► G: spot │ │
│ ├─► G: futures │ │
│ └─► G: options ────────┘─► Done() ──────┤
│ │
├─► G: coinbase ─┬─ endpointWg.Wait() ──┐ │
│ ├─► G: spot │ │
│ └─► G: futures ────────┘─► Done() ──────┤
│ │
└─► G: kraken... ─────────────────────────► Done() ──────┘