Buffered channels

Buffered channels are channels that have a bounded size. They are typically more performant than their unbounded counterparts. They are useful for retrieving values from an explicit number of goroutines that you've launched. Because they are FIFO (first in first out) queueing mechanisms, they can effectively be used as a fixed-size queueing mechanism, and we can process requests in the order in which they came in. Channels are created before they are used by invoking the make() function. Once a buffered channel is created, it is ready and available for use. Buffered channels don't block on incoming writes if there is still room in the channel. It's important to remember that data flows in the direction of the arrow within a channel. In our example (the following code block), we perform the following actions:

  • Write foo and bar to our buffered_channel
  • Check the length of the channel—the length is 2 because we've added two strings
  • Pop foo and bar off the channel
  • Check the length of the channel—the length is 0 because we've removed both strings
  • Add baz to our channel
  • Pop baz off the channel onto a variable, out
  • Print the resulting out variable, which is baz (the last element we added to the channel)
  • Close our buffered channel, indicating no more data is to pass across this channel

Let's have a look at the following code block:

package main
import "fmt"
func main() {
buffered_channel := make(chan string, 2)
buffered_channel <- "foo"
buffered_channel <- "bar"

// Length of channel is 2 because both elements added to channel
fmt.Println("Channel Length After Add: ", len(buffered_channel))

// Pop foo and bar off the stack
fmt.Println(<-buffered_channel)
fmt.Println(<-buffered_channel)

// Length of channel is 0 because both elements removed from channel
fmt.Println("Channel Length After Pop: ", len(buffered_channel))

// Push baz to the stack
buffered_channel <- "baz"

// Store baz as a variable, out
out := <-buffered_channel
fmt.Println(out)
close(buffered_channel)
}

This code can be found at https://github.com/bobstrecansky/HighPerformanceWithGo/blob/master/3-iterators-and-generators/channels/buffered_channel.go.

As we can see in our code block example, we are able to push data to the stack and pop data from the stack. It's also important to note that the len() built-in returns the number of elements that are unread (or queued) within the channel buffer. Alongside the len() built-in, we can also use the cap() built-in to deduce the total capacity of the buffer. These two built-ins used in conjunction can often be used to know the current state of your channel, especially if it's not acting the way you expect it to. It is also good to get in the habit of closing channels. When you close a channel, you are letting the Go scheduler know that there are no more values that will be sent across that channel. It's also important to note that if you attempt to write to a closed channel or a channel that has no room left in the queue, your program will panic.

The following program panics:

package main
func main() {
ch := make(chan string, 1)
close(ch)
ch <- "foo"
}

We'll get the error message shown in the following screenshot:

This is because we attempted to pass data (the foo string) to a channel (ch) that was already closed.

The following program also panics:

package main 
func main() {
ch := make(chan string, 1)
ch <- "foo"
ch <- "bar"
}

We'll see the following error message:

The program panics because the goroutine will block and wait. This error is then detected by the runtime and the program exits.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.135.80