This article assumes that you have read about Golang, and know the basics at least.
So let me start with the definition of concurrency, it's simply the execution of some code instructions at the same time. that's it.
Goroutines
A goroutine is a lightweight thread of execution.
A Thread, or thread of execution, is a software term for the basic ordered sequence of instructions that can be passed through or processed by a single CPU core. - stackoverflow.
so goroutine lets us execute functions concurrently, how is that? a simple example:
Output
so as you can see the output of this simple program is not in the function order, cause they are executed concurrently so the result can be unordered.
But wait a minute, why you put that time sleep at the end there ? is it necessary why is it necessary ?
The Go program is going to finish executing when the main function ends, So, Our two function calls are running asynchronously in separate goroutines now. Waiting for them to finish, but the main function doesn't wait it doesn't know that the two functions are still running, so if we remove that sleep it won't print anything to the console. try it if you want.
now lets go to channels.
Channels
Channels are the pipes that connect concurrent goroutines. You can send values into channels from one goroutine and receive those values into another goroutine.
lets start with code directly, here is an example using channels.
So let me first tell you what is the difference between this chan<-
, this <-chan
and this chan
.
"chan" => in the function parameter, means that we will read and write from that channel, it's a data type. "chan<-" => means that we will write only "<-chan" => means that we will read-only
the output of this program:
so in the main function we created a channel named done, we passed that channel as a parameter to our workers (createUser, and upload), and whenever a worker is done we notify the main function.
we put in the channel with channelName <- VALUE
and we consume the message from a channel like this <-channelName
if we don't consume the message, the goroutine function is not gonna print anything cause the main will not wait for it, so by using <-done
we are telling the main function to wait until we get a message from the worker.
so if we removed this line here
we will get an output like this:
so <-done
is simply blocking the main function from exiting. and therefore ending the program from executing.
And this is what is called Channel Synchronization, its just a fancy word that means blocking until a goroutine finish executing.
But, When waiting for multiple goroutines to finish, you may prefer to use a WaitGroup.
WaitGroup
To wait for multiple goroutines to finish, we can use a wait group.
Again, lets jump directly to code, and then i will explain how and why.
well, to use WaitGroup, we need to import the sync package, then we declared a global variable wg.
now let me explain how the WaitGroup works. the wg.Add(NUMBER_OF_GOROUTINES)
this function increment the number of the running goroutines, the wg.Done()
will decrease the number of goroutines, so whenever a worker (function) is done working you fire the wg.Done()
function the defer
keyword just tells the function to delay until the main function ends its work (by main function i mean its parent wich is the upload and create function), lastly the wg.Wait()
this function blocks the program from exiting until the number of goroutines is 0. so wg.Done()
will decrease until we reach the 0 then the wg.Wait()
will fire, and the program exit/finish.
Thanks for reading, this is my first post, so if there is anything !good let me know :)