Concurrency in Golang

Tram Ho

1. Introduction

Hello everyone, today I will introduce one of the fairly important topics in Golang, which is Concurrency. So does concurrency in Golang have new concepts, how do they work and how to use them? We will learn and answer together through this article

2. Concepts

Before going into specific examples, we will learn through new concepts related to Concurrency in Golang.

2.1. Goroutine

When it comes to concurrency, Golang gives us a new concept, which is Goroutine. So what is Goroutine?
Goroutine is a lightweight gadget managed by the Go runtime. Goroutine is a function that can run concurrently with other functions.
Syntax using Goroutine

2.2. Channel

The question arises, so how can goroutines communicate with each other? The answer here is that channel
Channels provide a way for goroutines to communicate with each other and synchronize their execution.
By default, the channel is bidirectional, which means goroutines can send or receive data across the same channel
The syntax for using channel

  • Declare 1 channel:

  • Send an element into the channel:

  • Get the element from the channel:

  • In the case the result of the received statement will not be used is also a valid statement. You could also write a receive statement like this:

3. Use Goroutine

Let’s start with a basic example when not using Goroutine.

It is easy to see that we have a function hello to print the greeting 5 to a specific name 0.5s apart, the main function will send a greeting to 2 names John & Peter
The result, we will get the following:

OK, so now let’s change to add goroutine to the two hello commands in the main function. Change the main function as follows:

When we run again you will see our program finished without printing anything. Why so?
The simple answer here is: in Go, when the main function ends, the program also ends, then all goroutines also end. In the above example, after running 2 goroutine commands, the program terminates so 2 goroutine has no time to run. Let’s adjust a little bit, we will sleep the main function again a bit and then check again with the following command at the end of the main function:

Oh, we get the following results immediately:

It can be seen that the sentences “Hello John” & “Hello Peter” are displayed alternately, proving that the above 2 goroutines have been run asynchronously as expected.

Channel

Now we will also go to channel examples – how goroutines communicate with each other.
Let’s write a simple example as follows:

Looking at the above example we can see that the main function initializes a channel of type int then calls the process method to send 3 values ​​to the channel. Finally, use the for function to print out the values ​​received by the channel.
Running the above code together, we will get the following output:

Oh, the 3 values ​​received are correct, but why is there a deadlock error?
Well, the reason is that the process method after sending 3 values ​​to the channel ends, while the main function is still waiting for the next value to be sent into the channel, but nothing can send any more to the channel. This results in the main function being wait forever … However, go can detect this problem (runtime problem, not compile time) and stop the program.
To handle this problem, very simply, we close the channel by adding the following close(c) command at the end of the process method and re-edit the loop that prints out the results received in the channel as follows:

=> So every time we receive a value from the channel, we check before that channel has been closed. If closed, we will stop the program. Then the program will end normally and the results will be as follows:

Or more simply, we just need to write the loop like this:

Buffered Channels

Next we come up with a simpler example, create a channel, then send the value in and get the following:

The following results:

Why so? We would expect the result to show a normal value of 1. However, here could be explained as follows:
When we initialize the channel with the command ch := make(chan int) , the mechanism here is that every time we send a value into the channel, goroutine will block until the value in that channel is retrieved. . In this case, the main program will be blocked and not able to reach the underlying value line. And so, Go discovers the problem of being wait forever and resolves the deadlock error again.
In case we send into the channel with 1 goroutine & receive channel in another goroutine, it can still work normally, the sending goroutine will block until goroutine receives value in the output channel, then the sending goroutine continues. work.
If you want to send multiple values ​​into the channel then there is that way. Go introduces a form of Buffered Channels . With this channel we can specify the size of the channel. Let’s edit the code as follows:

Using the command make(chan int, 2) means we have created a Buffered Channel with size = 2. Using this channel we will no longer have to worry about goroutine being blocked when sending message. The following results:

Of course if we intentionally send values ​​more than the size of the channel, a deadlock occurs.

Selection

Moving on, let’s go to the following example:

We create 2 channels & 2 goroutine, goroutine 1 will send the message “Sleep 1s” every 1 second, goroutine 2 will send the message “Sleep 5s” every 5s, then we print out the mesages received in channel 1 & 2. When trembling, we have the following results:

This is a timeout running program because we send in & out forever. However, let’s just ignore this problem and look at the results, we will see, even though goroutine 1 sends channel 1 message every 1s. But the main function has to wait for the message to be printed on channel 2 before it can continue to print the message in channel 1. That is why channel 1 is received every 1 second but prints out sequentially with channel 2 as 5s.
In order not to let channel 1 wait for channel 2 to receive further processing, we can use the select command in the for function as follows:

In this way we can receive the message channel 1 every time we have, without having to wait for channel 2 like the code above. And this is the result:

Conclude

Thus, through the above example I have introduced about concurrency in Golang, but specifically here is how goroutine works, how to use channel, select, … in Golang. These are just the fairly basic parts of concurrency in Golang, but hopefully this article can help you understand and apply in learning as well as work. Thank you for watching the article!

Share the news now

Source : Viblo