Buffered vs unbuffered Go channels and deadlock scenario
Tests channel synchronization semantics. Unbuffered channels block until sender and receiver rendezvous; buffered channels block only when full or empty. Deadlock: goroutine sends on unbuffered channel with no receiver.
WHAT THIS TESTS: This question tests whether you understand channels as a synchronization primitive rather than just a message queue. Interviewers want to see that you grasp the relationship between capacity and blocking behavior, and that you can predict runtime deadlocks from channel misuse.
A GOOD ANSWER COVERS: First, define capacity zero versus non-zero. An unbuffered channel has capacity zero, so every send blocks until a matching receive executes, and every receive blocks until a matching send executes; this creates a synchronous rendezvous. A buffered channel has capacity greater than zero, so a send blocks only when the buffer is full and a receive blocks only when the buffer is empty; this allows limited asynchrony. Second, explain ownership and happens-before guarantees. An unbuffered send completes only after the receive has accepted the value, giving a strong synchronization point. A buffered send completes as soon as the value is copied into the buffer, which means a receiver might not have run yet. Third, give a concrete deadlock. For example, a main goroutine creates an unbuffered channel, then sends a value on it without launching a receiver goroutine; because there is no other goroutine to receive, the send blocks forever and the program deadlocks. Alternatively, two goroutines each hold a value the other needs and attempt to send on unbuffered channels to each other, causing mutual blocking. Fourth, mention that buffered channels can still deadlock if a sender fills the buffer and no receiver drains it, so capacity is not a cure-all.
COMMON WRONG ANSWERS: Claiming that buffered channels are non-blocking or that they eliminate deadlocks entirely. Another red flag is describing the difference only in terms of queue length without mentioning the blocking semantics or synchronization implications. Some candidates also confuse channel direction with buffering, talking about send-only versus receive-only types instead of capacity.
LIKELY FOLLOW-UPS: How would you choose between buffered and unbuffered for a worker pool or a rate limiter? What happens when you close a buffered channel with unread values? Can you range over a nil channel? How does the Go runtime implement the blocking and waking of goroutines on channel operations?
ONE CONCRETE EXAMPLE: Consider a function that spawns a goroutine to process a job and wants to return the result through an unbuffered channel. If the function sends the job into the channel but the goroutine it just launched attempts to receive from a different channel, or if the function accidentally sends before starting the goroutine, the send blocks forever. A correct pattern is to launch the goroutine first so it is waiting to receive, or to use a buffered channel with capacity one so the send can complete immediately and the goroutine can return later.
Read the original → go101.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.