hi there serdar yagulov here for infoworld in this episode of smartgo i'm going to
talk about the safe way to concurrently access maps from multiple go routines maps
and go are not thread safe if you have multiple go routines making changes to the same map you'll
almost certainly run into a runtime error reading from a map from multiple go routines is generally
okay but anything where you want read write access to a map requires some additional work
now generally there's two ways to allow maps to be fully thread safe
one is to use the sync package's read write mutex object in conjunction with a map the other is to
use a special map type that is supplied by the sync package both of these have their use cases
so i'm going to go through them in turn first here's an example where we're using a mutex
in this code i have a structure with a map in it a mutex and a string builder object
the map consists of key strings and integer values and we also have a go routine in which we update
a value in the map and we will run three instances of that go routine and the way mutexes work
we need to explicitly lock and unlock them for whatever type of access we're going to perform
on the object we can use two types of locks a read-only lock where everyone can read but no one
can write and a write lock where we give exclusive permission to write from one go routine at a time
and this function do our go routine we use both of these types of locks we have a loop which iterates
300 times and for each iteration of the loop we take a right lock on the map and change it
and we also use the string builder to add a character to the string part of the structure
this is to measure our progress by the way you'll see a graphic example of why we're doing this in
a little bit and on every 50th turn of the loop we acquire a read lock on the struct print the value
from our map to the console and add an asterisk to the string of the struct again to indicate
our progress now if we run this code here is our output first we have the numbers that are printed
to the console from the read lock portion of the code and then we have all of these characters here
each which represents the behavior of each go routine a number indicates which go routine
is currently in action and the stars are the read lock operations from either go routine
you'll notice how these operations interleave with each other
although you'll notice that the interleaving is not perfectly consistent across multiple runs
it varies and big part because the scheduling of go routines is not inherently predictable
it's up to the thread scheduler in the go to go runtime to deal with such things
now to illustrate why we need to do the locking let's take out the locking and run this code again
and see what happens i should note that we may need to run this code a couple of times in order
to force an error but it will crash if you run it enough and as you can see we have a fatal
error concurrent map writes that it's thrown at runtime without the locking operations we
don't have any guarantees that writes to the map aren't going to overlap from different go routines
so now let's have a look at an example of the same operation but this time we're going to use
the sync packages built-in map type and the way a sync map works is a little bit different from
a regular map for one we need to use special methods to get and set values in a sync map
load and store on the plus side we don't have to perform any manual locking at all
the locking and synchronization are all handled internally so as you can see all the locking code
that we had in our earlier version is now gone now here's the other big difference with a regular map
we have to declare types for our key and value a sync map uses the empty interface as its base type
so we have to use type assertions whenever we retrieve values from it that makes read
and write operations a little clunkier but again we don't have to clutter the code with locking
and unlocking operations now if we run this you'll see that the behavior is quite simple
quite similar to the first example although the interleaving patterns may be a little different
presumably because of how sync map handles things under the hood but the basic idea is the same
so you may ask if sync map is easier to use why not just use it all the time well let's go to
the go documentation to tell us why and it says here that sync map is optimized for two use cases
one of them being when we have a map where keys are read many more times than they are written to
for instance a cache that grows indefinitely and the other is when you have go routines that read
write and overwrite entries for a disjoint set of keys in plain english this means they're working
on many different kinds of keys or many different keys not just one so clearly these are not
universal use cases they may be close enough to your use case to be worth trying but they're not
going to work in every circumstance the biggest reason to prefer a regular map plus a mutex as
opposed to the sync map version of the map is that regular maps require type definitions this
means that they're both faster and more type safe in your code sync map uses the empty interface as
its object type so it's slower at runtime if you know what types you're going to be using in your
map and you probably should then it makes the most sense to just use a mutex it'll speed things up
it'll also make your code easier to reason about again at the cost of a little boilerplate
but still the benefits from the predictability and speed of the code will probably be worth it
so to sum up the most common way to allow safe concurrent access to a map and go
is to use a read write mutex even if it requires a little boilerplate around the code
one can also use a sync map structure but that's best for specific use cases and it comes to the
cost of some performance because sync maps are not strongly typed they use the empty interface
that's it for this video if you liked it please leave a comment below don't forget
to subscribe to the tech talk channel on youtube and for more smart go and more dev
with serdar generally be sure to follow me on facebook youtube and infoworld.com