Skip to content

Instantly share code, notes, and snippets.

@magical
Created September 18, 2015 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save magical/9c6a1cc08556a7f50a76 to your computer and use it in GitHub Desktop.
Save magical/9c6a1cc08556a7f50a76 to your computer and use it in GitHub Desktop.
// https://blog.quickmediasolutions.com/2015/09/13/non-blocking-channels-in-go.html
// ...without using reflect
package util
import (
"container/list"
)
// Channel that does not block when items are sent. To use the struct, simply
// send on the Send channel and receive on the Recv channel. Items will be
// stored internally until they are received. Closing the Send channel will
// cause the Recv channel to be also be closed once all items are received.
type NonBlockingChan struct {
Send chan<- interface{}
Recv <-chan interface{}
}
// Create a new non-blocking channel.
func NewNonBlockingChan() *NonBlockingChan {
// Create the two channels that will be used for sending and receiving
var (
send = make(chan interface{})
recv = make(chan interface{})
)
// Assign the channels to the public members of the struct (which limits
// each of their direction)
n := &NonBlockingChan{
Send: send,
Recv: recv,
}
// Start a goroutine to perform the sending and receiving
go func() {
// Create the list that will temporarily hold items for receiving
items := list.New()
for {
// Close the Recv channel and quit if the Send channel was closed
// and there are no more items left in the list to send
if send == nil && items.Len() == 0 {
close(recv)
break
}
// If the list contains at least one item, add a select case to
// send the first item from the list on the Recv channel
var recvCase chan interface{}
var recvItem interface{}
if items.Len() > 0 {
recvCase = recv
recvItem = items.Front().Value
}
select {
case v, ok := <-send:
// If an item was received, add it to the list - otherwise,
// remove this case from the select statement by setting send to nil
if ok {
items.PushBack(v)
} else {
send = nil
}
case recvCase <- recvItem:
// The first item was sent, so it can be removed from the list
items.Remove(items.Front())
}
}
}()
return n
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment