In our last post, we talked about channels in Go. In this post we will go a little deeper into the concurrency features of Go has. Before we move on, we should briefly look at an overview of unbuffered and buffered channels.

Reviewing Channels

As we mentioned in the last post, by default channels are unbuffered. This means that they will only accept incoming values when there is a value that is being sent. The best way to look at this kind of behavior is to imagine train tracks. Imagine there are two parallel tracks that combine into one single track. In an unbuffered world, these tracks will always switch when there is exactly one train ready to cross. This means that if a train is coming from the right side, then the tracks will switch to that side. If a train is coming from the left side, then the tracks will switch to that side.

The trouble starts when we have multiple trains coming to the fork at once. The only way to resolve this problem is to use a buffering system. In this situation, one train will stop and wait while the other one crosses. If the buffer is increased then more trains can cross this fork without crashing into one another.train-switch

Like the metaphor, a buffered channel allows the program to send a specified number of values into a channel before they need to be received. Lets look at an example of this.

This example is very much like our metaphor. Both of our strings are trying to go into the channel before the channel is received. If we didn’t use a buffer then this would fail and cause a deadlock. A deadlock in Go is what happens when the switch between our two forking tracks can not decide which side to let through. As a result, both trains get stuck at the fork indefinitely.

Select in Go

Lets now look at another feature of Go’s concurrency model; Select. Select in Go allows a goroutine to wait for multiple communication operations to occur. The select operation will block the code until one of its cases is matched. It is a bit like a switch statement in this way.

If we have two or more channels and we want all of them to resolve at the same time we can use a select statement. Here is an example.

In this example, we have two channels both which are unbuffered. We run two anonymous functions concurrently to one another using goroutines. In these functions we pass a string to each of the channels. We then use our select operator to print out this message. We use a for loop to iterate twice through our select operator so that both cases are printed.go-channel

Like a switch statement, our select operator can also have a default case. This default case will try to execute when no other case is ready. Here is a simple example.

This example is pretty self explanatory. Based on the time after execution various events will happen as a result of the select operator.

Conclusion

In this post, we talked further about Channels and we introduced the select operator. We also talked further about channel buffering and how it works and we touched on deadlocks. In our next posts, we will start to look at the built in Http-server in Go using all of the concepts we’ve learned thus far.