Go

How do you do a non-blocking send or receive?

Question 201MediumGo 1.22 to 1.25

Use select with a default case. If no other case is ready, default runs right away.

// Non-blocking send: drop if the consumer is behind (e.g. metrics, logs)
select {
case events <- e:
default:
	dropped.Add(1)
}

// Non-blocking receive: poll
select {
case v := <-results:
	use(v)
default:
	// nothing yet
}

// Try-acquire on a semaphore channel
select {
case sem <- struct{}{}:
	defer func() { <-sem }()
	work()
default:
	return ErrBusy
}

Pitfall: a non-blocking receive inside a tight for loop is a busy-wait that burns a whole CPU core. If you're polling, you almost always want a blocking select with a timeout or ctx case instead. Also, a non-blocking send on an unbuffered channel only succeeds if a receiver is already parked at that exact moment, which is often surprising.

More on Channels & select

All 38 Channels & select questions