Hey we're now at the last video of this section using it all concurrent Singleton in the previous video
we dived into using channels in this video.
We'll put all our knowledge in a single package.
We'll create structure or variable that could only exist once in our code.
All access to this structure should be done using the pattern described but we'll write this with concurrency
in mind.
We'll write a concurrent counter like the one we wrote in the new text is video but this time we'll
solve it with channels.
So let's start by writing the unit test to restrict concurrent access to the Singleton instance.
Just one go routine we'll be able to access it will access it using channels.
The first one to add the second one to get the current count and the third want to stop the go routine
will add 1 10000 times using 10000 different go routines launched from 2 different Singleton instances.
Then we'll introduce a loop to check the count of the singleton until it is 5000 but we'll write how
much the account is before starting the loop.
Once the count has reached 5000 the loop will exit and quit the running go routine.
Now let us write the test code.
I've already created 2 files Singleton Dok Go and Singleton underscored test Doc go within the folder
channel underscore Singleton open the Singleton test Dok Go file here at these lines of code here what
you see is the full test which will use after creating two instances that Singleton.
We've created a for loop that launches the add one method 5000 times from each instance.
This is not happening yet they're being scheduled and will be executed eventually.
We are printing the count of the singleton instance to clearly see this eventuality depending on the
computer it will print some number greater than or equal to zero and lower than ten thousand.
The last step before stopping the go routine that is holding the count is to enter a loop that checks
the value of the count and waits 10 milliseconds if the value is not the expected value that is ten
thousand.
Once it reaches its value the loop will exit and we can stop the Singleton instance will jump directly
to the implementation as the requirement is quite simple move to Singleton Dok Go and start with the
implementation first of all will create the go routine that will hold the count.
Okay.
We created three channels as we mentioned earlier the ADC each channel is used to communicate with the
action of adding one to the count and receives a bool type just to single add one we don't need to send
the number although we could be get count c h channel will return a channel that will receive the current
value of the count.
Take a moment to reason about the get count see a channel.
It's a channel that receives a channel that receives into times.
It sounds a bit complicated but it will make more sense when we finish.
Example Don't worry the quit C channel will communicate to the go routine that it should end its infinite
loop and finish itself to.
Now we have the channels that we need to perform the actions we want.
Next we launch the go routine passing the channels as arguments as you can see we're restricting the
direction of the channels to provide more type safety inside this go routine we create an infinite for
loop this loop won't stop until a break is executed within it.
Finally the select statement if you remember was a way to receive data from different channels at the
same time.
We have three cases so we listen to the three incoming channels entered his arguments first one is the
ADC case which will add one to the count.
Remember that only one case can be executed on each iteration.
So no go routine could be accessing the current count until we finish adding one next the get count
see each channel receives a channel that received an integer.
So we capture this new channel and send the current value through it to the other end.
Then the quick CHF channel breaks the for loop so the go routine ends.
One last thing.
The init function in any package will get executed on program execution so we don't need to worry about
executing this function specifically from our code.
Now we'll create the type.
The tests are expecting we'll see that all the magic and logic is hidden from the end user in this type.
As we've seen in the code of the test let's add the type Singleton struct also lets out the package
name find the Singleton type won't hold the account value we created a local value for it called instance
and we return the pointer to this instance when we call the get instance method.
It's not strictly necessary to do it this way but we don't need to allocate a new instance of the singleton
type every time we want to access the accounts variable first the add one method will have to add one
to the current count how by sending true to the ADC each channel.
That's simple.
So let's add the code for this this small snippet will trigger the ADC each case in our go routine in
turn the ADC HK simply executes count plus plus and finishes letting select channel control flow that
is executed on init function above to execute the next instruction so we add the next lines of code
with this instruction he get count method creates a channel every time it's called and defers the action
of closing it at the end of the function.
This channel is on buffered as we've seen previously in this section and buffer channel blocks the execution
until it receives some data.
So we send this channel to get count C H which is a channel 2 and effectively expects a channel type
to send the current count valley back through it to get count method will not return until the value
of count variable arrives to the rez.
C H channel he might be thinking why aren't we using the same channel in both directions to receive
the value of the count.
This way we will avoid an allocation.
Well if we use the same channel inside the get count method we'll have two listeners in this channel
one in select statement at the beginning of the file on the init function and one there.
So it could resolve to any of them when sending the value back.
Let's add some more lines of code to our file.
Finally we have to stop the go routine at some moment the stop method sends the value to the Singleton
type go routine so that the quit c h case is triggered and the for loop is broken.
The next step is to close all channels so that no more data can be sent through them.
This is very convenient when you know that you won't be using some of your channels anymore time to
execute the tests and take a look.
Save the file a move back to the terminal we need to save test fall to done now run the command go test
hyphen v very little code output but everything has worked as expected in the test we printed the value
of the count before entering the loop that iterate until it reaches the value 10000 as we saw previously
B go scheduler we'll try to run the content of the go routines using as many OS threads as you can configured
by using the Go Max proc configuration in my computer it set to 4 because my computer has 4 course but
the point is that we can see that a lot of things can happen after launching a go routine or ten thousand
and the next execution line but what about its uses of new taxes I show you the code which you can use
for this let's create another folder and name it as locks underscore Singleton and within this we create
two files Singleton Dok Go and Singleton test dot go file open the Singleton dot go file and add the
code which will be explaining now similarly to the Singleton test dot go file we use the same test we
used previously.
Let's get back to Singleton dot go and try to understand the code we wrote here in this case the code
is much leaner as we saw previously we can embed the new text within the Singleton structure the count
is also held in the account field and the add one and get count methods lock and unlock the values to
be concurrently safe.
One more thing in this Singleton instance we're using the RW mutates type instead of the already known
sync dot mutates type.
The main difference here is that the RW mistakes typos two types of locks are read lock in a right lock
the read lock executed by calling the R lock method only whites have a right lock is currently active
at the same time it only blocks a right lock so that many read actions can be done in parallel it makes
a lot of sense we don't want to block a go routine that wants to read a value just because another go
routine is also reading the value it won't change the sync dot r w new text types helps us to achieve
this logic in our code that's over this video in this section we've seen how to write a concurrent Singleton
using new Texas and channels while the channels example was more complex it also shows the core power
of goes concurrency as you can achieve complex levels of event driven architectures by simply using
channels just keep in mind that if you haven't written concurrent code in the past it can take some
time to start thinking concurrently in a comfortable way but it's nothing that practice cannot solve
we've seen the importance of design and concurrent apps to achieve parallelism in our programs we've
dealt with most of those primitives to write concurrent applications and now we can write common concurrent
design patterns in the next section we'll be learning about the barrier future and pipeline design patterns.