This is mainly an exercise in examining ways in which you can write code in a non blocking style. The mutex available in the sync package is a perfectly acceptable way of protecting memory from bad things happening — un synced writers for example.
Also I should point out that “Share memory by communicating” very much still stands as a mantra you should keep in mind when writing Go.
There are a few examples of code that can block — either by using a mutex, or reading from a chan in a slow manner. Also there are certain data structure in Go that aren’t thread safe, for example maps, or bools.
In Go, the bool type isn’t inherently safe to use by multiple goroutines. We can protect it in a few ways.
This first bit of code shows how to use a simple mutex to lock a variable while it’s being updated.
Very simply, the mutex stops any other goroutine from updating the internal state of the SimpleBool struct when another goroutine has locked it.
Using Go’s built in benchmarking, it’s simple to see how this is performing.
and the results.. drum roll please!
So pretty quick and no allocations — at least not after you have created the initial variable. But is there a way to make it quicker and not use the mutex?
Go has another package within sync called Atomic. Looks interesting, right? With a few tweaks we can add some atomic goodness in place of the mutex.
So instead of locking the state of the safebool struct so only one actor has the ability to change it, we’re making each change to the state of safebool an atomic action. That is to say, Go takes over and makes sure that these actions safe and atomic so that even if multiple goroutines use a safebool variable at the same time their actions won’t interfere with each other.
Throwing some benchmarks at it we can see how it fares against the mutex version.
If it’s not completely obvious, there’s a huge performance increase here. We’re looking at about 140 ns for each operation in the Mutex version, whereas we’re down to 32 ns for a Set and a whole 6 ns!! for each Get. That’s a ~23x speedup. cool huh?
There is a subtle difference here between using a Mutex and the Atomic functions. The Mutex is far more generic and allows you to do whatever you want to the protected value. When we use the Atomic version, that action on the protected value is far more distinct and we know exactly what we want to do to the variable — set an int — therefore we don’t have any of the waiting for other goroutines to unlock that is found in the Mutex.
As I said above, I’m not telling you to go out and remove ALL your mutex’s and replace them with some atomic versions. It’s purely an interesting experiment to see what is possible and if indeed it makes sense.
Some lines from the Go Memory Model will stand you in good stead in this regard..
If you must read the rest of this document to understand the behavior of your program, you are being too clever.
Don’t be clever.
Part 2, we’ll look at some variable swapping and possibly see if we can protect some other types while trying to be exceedingly clever.
See any problems in this post? Leave a comment, or tweet me - Mat Evans
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising &sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!
Create your free account to unlock your custom reading experience.