Send Receive Operations
Fast recall
Quick revision
Core answer
Whether you understand Send Receive Operations beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The two operators are the whole channel interface:
ch <- 42 // send 42 into ch
v := <-ch // receive from ch into v
<-ch // receive and discard (fire-and-forget drain)Arrow points in the direction of data flow: ch <- v pushes into the channel, <-ch pulls out of it. The mnemonic: the arrow shows where the value goes.
On an unbuffered channel, each operation is half of a rendezvous. The send blocks until a receiver is ready; the receive blocks until a sender is. Whichever happens first waits; when the second arrives, the value transfers and both continue. That blocking IS the feature — it's why an unbuffered send returning is proof that someone received.
On a buffered channel: the send only blocks when the buffer is full; the receive only blocks when the buffer is empty. Values queue in between — the buffer absorbs the timing gap.
The operators also compose into other syntax: v, ok := <-ch (comma-ok — ok is false if the channel is closed and drained), and for v := range ch (receive until close). Those forms cover the three questions a receiver has: give me a value, is this channel still alive, and give me everything until it's done.
Send Receive Operations
Direct Answer
ch <- v sends v; v := <-ch receives. On an unbuffered channel both operations block until the other side is present — the send/receive meet is the synchronization.
Deep Dive & Architecture
Under the operators: both send and receive take the channel's lock, check the wait queues, and either complete on the fast path or park. The interesting mechanics are the two rendezvous cases:
Sender arrives, no receiver, buffer full: the sender goroutine is parked, and — this is the elegant part — the VALUE it's sending is parked WITH it: the runtime copies the value into the sender goroutine's own stack slot and links that goroutine into the channel's send queue. When a receiver later arrives, it locks the channel, finds a parked sender, copies the value directly from the sender's stack into the receiver's result — goroutine-to-goroutine, buffer never involved.
Receiver arrives first, no sender: parks on the recv queue with a pointer to its own stack slot for the eventual copy. When a sender arrives on a channel with waiting receivers, the value copies straight sender→receiver, bypassing the buffer even on a buffered channel.
Those two direct paths explain the performance folklore: an unbuffered channel send+receive pair is one copy and two lock operations — the 'rendezvous' is literally two stacks meeting through the channel's lock, and the value is copied once. A buffered send+receive is two copies (sender→buffer, buffer→receiver) but the two sides never have to be scheduled together. That's the mechanical trade: unbuffered trades a scheduling dependency for one fewer copy.
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use Send Receive Operations in a real project?
- How would you compare Send Receive Operations with an alternative?
- What is a common mistake when using Send Receive Operations?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.