When would you use Channel Creation in a real project
Fast recall
Quick revision
Core answer
Practical understanding of Channel Creation.
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 difference is what a send does when no one is receiving.
Unbuffered (make(chan T)) — the send parks the sending goroutine until another goroutine executes a receive on the same channel. The value transfers directly from sender to receiver; nothing is stored in between. The completion of the send and the completion of the receive are the same moment. That's a synchronization guarantee: when ch <- v returns, you KNOW some receiver has your value.
ch := make(chan int) // unbuffered
ch <- 42 // blocks until someone executes <-chBuffered (make(chan T, n)) — the send copies the value into the channel's buffer and returns immediately, as long as the buffer has a free slot. The sender only blocks when the buffer is full. A receiver drains the buffer at its own pace.
ch := make(chan int, 2) // buffered
ch <- 1 // returns instantly — slot 0
ch <- 2 // returns instantly — slot 1 (buffer now full)
ch <- 3 // would block: no free slotExecuted: the first two sends complete without any receiver existing. With cap 2 and len 2, the third send would block.
The choice is protocol design. Unbuffered when the exchange itself is the synchronization — hand-offs where the producer shouldn't run ahead (a job must be picked up before the next is made). Buffered when you're decoupling rates — a producer that bursts, a consumer that drains, and n is how much slack you tolerate.
When would you use Channel Creation in a real project
Direct Answer
Unbuffered: every send blocks until a receiver takes the value — a rendezvous, synchronization built in. Buffered: sends fill slots (up to capacity) without blocking; senders run ahead of receivers.
Deep Dive & Architecture
Mechanically, the hchan struct has a ring buffer (allocated by make with the capacity), and every send/receive follows the same path:
send: lock the channel. If the buffer has a free slot, copy the value in, wake a waiting receiver if any, unlock, return — fast path, no parking. If the buffer is full (or the size is 0 — unbuffered means a size-0 ring, so 'is it full' is trivially yes), enqueue the goroutine on the send-wait queue and park — until a receive frees a slot and wakes it.
receive: the mirror. A value in the buffer: take it, wake a waiting sender if any. Empty buffer: park on the receive-wait queue.
The rendezvous detail in the unbuffered case: with size 0, the 'buffer' never holds anything — a receiving goroutine's stack slot is used directly as the destination, and the runtime copies sender→receiver when both are present. This is why the unbuffered send completing is a proof of the receive: the copy only happens when both sides exist at the same scheduling point.
The subtle behavioral difference that bites in production: buffered channels defer backpressure. With unbuffered, a slow consumer slows the producer immediately (the send blocks) — natural flow control. With buffered, the producer only feels the consumer when the buffer fills — latency of feedback = n items. Choosing n is choosing how far ahead the system can run before it notices a problem. That's not a performance knob; it's a failure-detection knob.
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 Channel Creation, and when would you use it?
- How would you compare Channel Creation with an alternative?
- What is a common mistake when using Channel Creation?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.