Golang Tutorial — Goroutines and Channels

Can Tepakidareekul
4 min readOct 20, 2019

--

From the very first article of Golang tutorial series, I had mentioned about the advantages of this language which is very good concurrency management. It means that you can create a program with concurrency by using Go easily, and the program will work with high performance. In this article, I will show you how to create the programs with concurrency by using Goroutines and Channels which are the Go’s features. So, let’s do it!

Goroutines

A goroutine is a lightweight thread managed by the Go runtime.

The message above is from Go official website, but if you still can’t understand it. Let you see the example below.

As you can see, there are two functions called waitAndPrint which will wait for one second and display a message and printAndWait which will display a message before waiting for two seconds, and there is statement go in front of the waitAndPrint function to run this function on new lightweight thread which is called goroutine. While printAndWait function runs on main thread. So, instead of printing “Hello” before “Bye”, the output will be “Bye” before “Hello” because “Hello” need to wait for 2 seconds before being printed.

A goroutine won’t be terminated, even the caller function/goroutine is already terminated. A goroutine will be terminated only if main function is already terminated, or the goroutine has already done its job. Like what happens in the example above, print1 function which is the caller of print2 is terminated before print2, but the message from print2 is still printed.

Channels

Now we know how to create goroutine, but it must be better if we can communicate between each goroutine or between goroutine and main thread. Channel is the feature that will help us do that. Let take a look at the example below.

It’s very easy to declare channels by putting chan statement in front of data type. You can pass a value in form of any data type via a channel. As you can see in the example, data (10) is pass into the channel (c <- 10) and the data is received by putting an arrow in front of the channel.

Sending (c <- ) statement will be blocking until these is receiving (<- c) statement, and it also happens in the other way around.

Buffered Channels

If you don’t want your program to be blocked by sending statement, a buffered channel is your choice.

The example above is the blocking case, means that sender needs to wait for receiver to get the data out of the channel. You can see from the output the message “SENDER DONE” is printed after the receiver prints all the numbers.

The example above is almost the same as the previous one, but the different thing is that there is the second parameter in the make function (c := make(chan int, n)). This number is the size of buffer. The sender can keep sending data in to the buffered channel without waiting for receiver until the buffer is full. As you can see the output, the message “SENDER DONE” is the first line, it means that the sender already finished its job before the receiver starts working.

Range and Close

We can improve the sender-receiver code by using range statement and close function with a channel. Like other iterable variable, you can use range with channels to iterate through them. And using close to inform the receiver that the channel is already closed to stop getting data from it.

Select

Select statement is the feature that allows you to wait for multiple channels at the same time. It works like switch-case statement, but for each case it needs to be a channel receiver statement. And there is default statement, you can use it if there is no data from any channel at that moment.

Mutual Exclusion

To control the concurrency, we need to prevent multiple goroutines to access or modify any shared data at the same time.

From the example, the program tries to increase n for 1000 times. So the result what we expected is 1000 but it’s not like that because there are multiple goroutines try to update the value at the same time, so the value they have might not be up-to-date.

And this is how to solve that problem, we can use sync.Mutex to prevent multiple goroutines to access the critical session which is increasing the number at the same. Anyway, you need to be careful when you are using mutex because you might face deadlock problem accidentally, and it is kind of hard to solve. Another thing you need to care about is that overusing mutex can slower you program. Instead of being concurrency, mutex can make your program runs sequentially.

And all of these features can help you to create a program with concurrency and help you to control it in Go. I hope you can see how easy it is, compare to other languages. Anyway, it still depends on how you design the concurrency in your program. If your design is good, your program will be fast and have no bugs. On the other hand, if your design is bad, I think you should know what will happen no matter what language you use. 😂

Recommend Articles

--

--