Concurrency in Go (Part 1)
Let's explore the most important feature in Go, Concurrency. We are going to be introduced by Goroutines and Channels here. They are built-in features in Go, not libraries. In part 1, let's get familiar with the concept and syntaxes.
Concurrency is the ability to be executed out-of-order without affecting the outcome. It is about executing multiple stuff at the same time and not in a particular order. Let's make some code to understand this concept.
Goroutines
|
|
Let's execute the code above. A goroutine is a lightweight thread managed by the Go runtime. As we can see from the code above, we put the go
syntax before the count
function. That means we put the count
function in a goroutine. We slept for 3 seconds means counting to 3. Let's try to remove the go
syntax. It would be a different result.
Channels
|
|
The similarity of our code above with the previous one is we have the same result.
Let's count! 1 2 3 Enough counting!
The difference is that our code above uses a channel inside a variable called c
with int
as the data type. The chan
syntax before the int
means we defined a channel for the integer type. It has the same result as the previous one. We counted the i
variable 3 times is equal to 3 seconds because a second happened in the count
function every time we put the i
into the channel, c
, with the <-
syntax.
Remember, they are out of order. But we just made it in order using a trick such as channels and time.Sleep
. You can play around with the code to make the result out of order.
Buffered Channels
|
|
We got a 3 seconds delay while defined the counts. Let's set the initCount
to be more than 3. We will get an error because the provided buffer length is 3. If we set the initCount
to be lower than 3, we will get the same error because that is lower than how we printed it, printCount
.
fatal error: all goroutines are asleep - deadlock!
Channels can be buffered. Provide the buffer length as the second argument to make to initialize a buffered channel. Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
Range and Close
|
|
We counted using the range
syntax for the channel. We put the i
to the channel under the provided buffer length using the cap
syntax. We closed the channel to indicate that no more values will be sent using the close
syntax.
value, receive := <-c
fmt.Println(value)
fmt.Println(receive)
You can put the code above before or after printing the channel. The boolean receive
is to check whether the channel receives the value or not and the value
is the current value of the channel.
Select
|
|
We have two channels here. The c
is to count. The quit
is to quit. The select
statement lets a goroutine wait on multiple communication operations. It looks similar to the switch
syntax.
Default Selection
|
|
The result of the code above is below.
Let's count! ..1 ..2 ..3 Enough counting!
The default
case in a select
is run if no other case is ready. Use a default
case to try a send or receive without blocking.
Closing
Maybe in the next part, we will try to implement this in the app or explore the advanced feature. You can get the source code on https://github.com/aristorinjuang/concurrency_01.
References
Related Articles
- Go Crash Course (Part 2)
- Go Crash Course (Part 1)
- Simple REST API with Go
- Intel Edge AI Scholarship Foundation Course, OpenVINO Fundamentals
- Microservices