What is the difference between buffered and unbuffered channels in terms of synchronization semantics?
An unbuffered channel (make(chan T)) is a rendezvous: a send blocks until a receiver is ready, and a receive blocks until a sender is ready. The handoff is synchronous, and the Go memory model guarantees that the receive completes before the send returns, so the sender knows the value was taken.
A buffered channel (make(chan T, n)) decouples the two sides up to n elements. A send blocks only when the buffer is full, and a receive blocks only when it is empty. The sender gets no confirmation that anyone has consumed the value.
done := make(chan struct{}) // unbuffered: acts as a signal/handshake
jobs := make(chan int, 100) // buffered: absorbs bursts, queue semantics
What the interviewer wants to hear: buffering is a performance and decoupling tool, not a correctness tool. If your program only works with a buffer of size N, you probably have a hidden deadlock that a larger load will expose. Use buffer size 1 on purpose for things like "fire and forget one result" (so a goroutine that times out doesn't leak), or for semaphores sized to a concurrency limit.
More on Channels & select
- Q184Describe the runtime internals of a channel (
hchan). - Q185Give the complete table of channel operation behavior for nil, open, and closed channels.
- Q186What does this print? (receiving from a closed buffered channel)
- Q187Explain the comma-ok idiom on channel receive. When is it needed and when is
for rangebetter? - Q188Who should close a channel, and why? What are the rules?
- Q189How do you safely close a channel that might be closed by multiple goroutines?