====== Go select with Non-blocking Send and Receive ======
===== Overview =====
In Go, the select statement allows a goroutine to wait on multiple channel operations.
When combined with a default case, select can be used to perform non-blocking send and receive operations on channels.
📌 non-blocking /nɒn ˈblɒk.ɪŋ/
→ does not wait; continues immediately
===== Basic Concept =====
Normally, sending to or receiving from a channel may block if:
the channel is full (send)
the channel is empty (receive)
no goroutine is ready on the other side
Using select with default avoids blocking by trying once and moving on.
📌 block /blɒk/
→ pause execution and wait
===== Non-blocking Send =====
A non-blocking send attempts to send a value on a channel without waiting.
==== Syntax ====
select {
case ch <- value: // send succeeded
default: // send would block, so skip
}
==== Explanation ====
If the channel can accept the value:
the send happens immediately
If the channel cannot accept the value:
the default case runs
the goroutine continues execution
📌 attempt /əˈtempt/
→ try to do something
📌 accept /əkˈsept/
→ receive or take in
===== Non-blocking Receive =====
A non-blocking receive attempts to receive a value only if one is available.
==== Syntax ====
select {
case value := <-ch: // receive succeeded
default: // no value available
}
==== Explanation ====
If a value is available:
it is received immediately
If no value is available:
default executes
execution continues without waiting
📌 receive /rɪˈsiːv/
→ get or take something
📌 available /əˈveɪ.lə.bəl/
→ ready to be used
===== Buffered vs Unbuffered Channels =====
==== Unbuffered Channel ====
ch := make(chan int)
Send and receive must happen at the same time
Non-blocking send will fail if no receiver is ready
Used for synchronization
📌 synchronization /ˌsɪŋ.krə.naɪˈzeɪ.ʃən/
→ coordinating actions to happen together
==== Buffered Channel ====
ch := make(chan int, 2)
Channel can hold values temporarily
Non-blocking send succeeds if buffer is not full
Non-blocking receive succeeds if buffer is not empty
📌 buffer /ˈbʌf.ər/
→ temporary storage area
===== Common Mistakes =====
==== Ignoring the result of append-like behavior ====
select {
case ch <- v:
default:
}
If the send fails, the value is silently dropped.
📌 silently /ˈsaɪ.lənt.li/
→ without any warning or message
==== Using len(ch) to decide send/receive ====
This is unsafe:
if len(ch) < cap(ch) {
ch <- v // race condition.
}
📌 race condition /reɪs kənˈdɪʃ.ən/
→ bug caused by timing between goroutines
Always prefer select.
===== When to Use Non-blocking Channel Operations =====
Use non-blocking send/receive when:
you want to avoid deadlocks
dropping data is acceptable
implementing polling or event loops
building soft real-time systems
📌 deadlock /ˈded.lɒk/
→ program stops because goroutines wait on each other
📌 polling /ˈpəʊ.lɪŋ/
→ checking repeatedly
===== Key Takeaways =====
select + default enables non-blocking behavior
Non-blocking send = try to send once, never wait
Non-blocking receive = try to receive once, never wait
Works best with buffered channels
Safe and idiomatic Go concurrency pattern