Golang / Golang Internals and Memory Management Interview Questions
When should you use channels versus mutexes in Go concurrency?
Go's concurrency mantra is "Do not communicate by sharing memory; instead, share memory by communicating." Channels are the primary tool for passing ownership of data between goroutines; mutexes are for protecting shared state that multiple goroutines need to access concurrently.
| Scenario | Preferred Tool |
|---|---|
| Passing ownership of data between goroutines | Channel |
| Signalling an event (done, cancel, ready) | Channel (or context.Context) |
| Pipeline of work items | Channel |
| Fan-out / fan-in patterns | Channel + sync.WaitGroup |
| Protecting a shared cache or counter | Mutex (sync.Mutex or atomic) |
| Read-heavy shared config or registry | sync.RWMutex or sync.Map |
| Updating a struct's fields | Mutex protecting the struct |
// ââ Channel: ownership transfer ââ func producer(out chan<- int) { for i := 0; i < 10; i++ { out <- i // transfer ownership of i to consumer } close(out) } func consumer(in <-chan int) { for v := range in { fmt.Println(v) } } // ââ Mutex: protecting shared state ââ type Inventory struct { mu sync.Mutex items map[string]int } func (inv *Inventory) Add(name string, qty int) { inv.mu.Lock() defer inv.mu.Unlock() inv.items[name] += qty } // ââ Avoiding channel misuse ââ // Bad: using a channel as a simple mutex replacement sem := make(chan struct{}, 1) // semaphore sem <- struct{}{} // acquire // critical section <-sem // release // Better: just use sync.Mutex for this pattern // Context for cancellation (not raw channels) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() select { case result := <-doWork(ctx): fmt.Println(result) case <-ctx.Done(): fmt.Println("timeout:", ctx.Err()) }
More Related questions...