====== 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