Why Go ?
Go has been widely used in most of the popular production systems such as Kubernetes, Docker, Influx DB, etc. There are mainly 4 reasons behind adoption of Go at such a massive scale.
- It's simple and elegant
- Provides built-in concurrency at scale
- Designed to run on multiple cores
- It's Super fast performance ๐
Goroutine is a way to achieve concurrency in Go ๐ฅ.
What is a goroutine ?
A goroutine is a lightweight thread managed by the Go runtime. Unlike Operating System thread which consumes memory usually in the range of MBs to function properly these goroutines consume memory only in the range of KBs. So it's easy and fast for go runtime to create goroutines than threads for concurrency. Goroutines are not actual threads, these are multiplexed to actual OS threads or even you could assume that these goroutines are a kind of abstract layer over OS threads.
Due to it's very small memory footprint, it's easy for go runtime to create thousands of goroutines in a fraction of milliseconds. But creating thousands of OS threads is heavily dependent on memory and the CPU, so it's obviously slow compared with goroutines.
As well as Goroutine does not have a Local Storage as a result goroutines are cheaper to implement than OS threads, so goroutines are much faster in terms of boot time.
Context switching is also faster in case of go
than OS thread context switching, because OS threads are heavy resources.
On top of this Go even has another coolest feature i.e. Channels๐ฅ. Channels are the built-in way to communicate with goroutines. In the case of OS threads, this communication is the most difficult thing you can think of.
So this how go achieved better concurrency than traditional programming languages, which made go a default language of choice for most of the use cases.
Syntax for goroutine
The most difficult part of goroutine is to understand it more than its real implementation. So take your time to understand it before diving deep into the actual implementation.
In other programming languages you might have used the async await
pattern for concurrency(Node.js and python - async await). But here it's even simpler than that. Just add the go
keyword to your function prefix( e.g : go someFunctionName
), now go runtime executes the same function in concurrency mode. See how cool is this ๐.
go addTwoNumbers(1, 2)
Implement a program without goroutine
Below is the snippet for adding 2 numbers. The addition
function has a sleep
command to mimic the processing time.
If you execute the program using the go run sequential.go
command, you will get the output as below(result as summation of 2 numbers).
Implement a program with goroutine
Now let's convert this sequential execution to concurrency by adding go
to the prefix of the caller. Below is the snippet.
If you execute now using this go run concurrency_without_wg.go
command, you will immediately notice that the output of addition function is not displayed.
If you reached this far, then you have successfully executed your first program in concurrency mode ๐ฅ.
But why is there a discrepancy in the output ?
This is happening because go runtime is not waiting for goroutines to finish their execution. So you need to explicitly update the details about goroutines to go runtime. This is where wait groups
comes into picture. That's the exact problem wait groups solve.
What are Wait groups ?
WaitGroup(sync.WaitGroup
) is a mechanism to wait till the collection of goroutines finishes their tasks.
There are mainly 3 helper functions available in golang to implement this feature.
- Add()
- Wait()
- Done()
Add(5)
method takes an integer as an argument. This integer represents the number of goroutines available in this collection to the go runtime. Wait()
tells the go runtime to wait exactly at this position till the collection of goroutines finishes their execution. Done()
method is used to inform go runtime that this particular goroutine finished its execution.
Below is the code snippet with 1 goroutine. Refer to the comments for deeper understanding.
If you execute now, you will get the desired output as below.
Summary
You have successfully implemented goroutines ๐ฅ, but without channels (A way to communicate with goroutines) this topic is never gonna be completed.
To stay updated on Channels
you can follow this blog.
I would ๐ to hear your feedback and comments on the great things you're gonna build with this. If you are struck somewhere feel free to comment. I am always available.
If you feel this article is helpful for others then please consider a like.
You can find the complete code at github