is the adress value return by map.LoadOrStore the same as the input in case of nested maps? - go

I'm doing a nested sync.Map but I wonder if I can save some few lines of code if the value returned by LoadOrStore is the same as the input in case of a map, I mean this:
var mapa sync.Map
mapaInterFace, ok := sessiones.LoadOrStore(userID,mapa)
if ok {
mapa,ok=mapaInterFace.(sync.Map)
if !ok{
return errors.New("type assertion")
}
}
If mapa were the same as the returned by LoadOrStore when the value is stored, I can immediately use it, but if not I have to add after the previous code, the type assertion:
mapa,ok=mapaInterFace.(sync.Map)
if !ok{
return errors.New("type assertion")
}
and doing some often it can make some ugly code
Update: sessiones is type sync.Map

As I explain later, you should use pointers for the sync.Map types. Therefore, we can simplify to:
var mapa, mapb = new(sync.Map), new(sync.Map)
var key string
if actual, loaded := mapa.LoadOrStore(key, mapb); loaded {
if maps, ok := actual.(*sync.Map); ok {
mapb = maps
} else {
// handle loaded value type assertion error
}
}
Now the assignments are cheap because we are assigning pointers (*sync.Map) not structs (sync.Map).
Package sync
import "sync"
type Map
Map is like a Go map[interface{}]interface{} but is safe for
concurrent use by multiple goroutines without additional locking or
coordination. Loads, stores, and deletes run in amortized constant
time.
The Map type is specialized. Most code should use a plain Go map
instead, with separate locking or coordination, for better type safety
and to make it easier to maintain other invariants along with the map
content.
The Map type is optimized for two common use cases: (1) when the entry
for a given key is only ever written once but read many times, as in
caches that only grow, or (2) when multiple goroutines read, write,
and overwrite entries for disjoint sets of keys. In these two cases,
use of a Map may significantly reduce lock contention compared to a Go
map paired with a separate Mutex or RWMutex.
The zero Map is empty and ready for use. A Map must not be copied
after first use.
type Map struct {
// contains filtered or unexported fields
}
func (*Map) LoadOrStore
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
LoadOrStore returns the existing value for the key if present.
Otherwise, it stores and returns the given value. The loaded result is
true if the value was loaded, false if stored.
A sync.Map must not be copied after first use.
In Go, all arguments and receivers are passed by value, as if by assignment (a copy). For example, go vet reports a sync.Map copy error,
// go vet: variable declaration copies lock value to arg: sync.Map contains sync.Mutex
var m sync.Map
var arg interface{} = m
and
var map1, map2 sync.Map
// go vet: call of map1.LoadOrStore copies lock value: sync.Map contains sync.Mutex
map1.LoadOrStore("key", map2)
Use pointers. For example,
var m sync.Map
var arg interface{} = &m
and
var map1, map2 sync.Map
map1.LoadOrStore("key", &map2)

Related

Using a mutex within a struct in Go

I see in Essential Go that using a mutex within a struct is not too straight-forward. To quote from the Mutex Gotchas page:
Don’t copy mutexes
A copy of sync.Mutex variable starts with the same state as original
mutex but it is not the same mutex.
It’s almost always a mistake to copy a sync.Mutex e.g. by passing it
to another function or embedding it in a struct and making a copy of
that struct.
If you want to share a mutex variable, pass it as a pointer
*sync.Mutex.
I'm not quite sure I fully understand exactly what's written. I looked here but still wasn't totally clear.
Taking the Essential Go example of a Set, should I be using the mutex like this:
type StringSet struct {
m map[string]struct{}
mu sync.RWMutex
}
or like this?
type StringSet struct {
m map[string]struct{}
mu *sync.RWMutex
}
I tried both with the Delete() function within the example and they both work in the Playground.
// Delete removes a string from the set
func (s *StringSet) Delete(str string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.m, str)
}
There will obviously be several instances of a 'Set', and hence each instance should have its own mutex. In such a case, is it preferable to use the mutex or a pointer to the mutex?
Use the first method (a plain Mutex, not a pointer to a mutex), and pass around a *StringSet (pointer to your struct), not a plain StringSet.
In the code you shared in your playground (that version) :
.Add(), .Exists() and .Strings() should acquire the lock,
otherwise your code fits a regular use of structs and mutexes in go.
The "Don't copy mutexes" gotcha would apply if you manipulated plain StringSet structs :
var setA StringSet
setA.Add("foo")
setA.Add("bar")
func buggyFunction(s StringSet) {
...
}
// the gotcha would occur here :
var setB = setA
// or here :
buggyFunction(setA)
In both cases above : you would create a copy of the complete struct
so setB, for example, would manipulate the same underlying map[string]struct{} mapping as setA, but the mutex would not be shared : calling setA.m.Lock() wouldn't prevent modifying the mapping from setB.
If you go the first way, i.e.
type StringSet struct {
m map[string]struct{}
mu sync.RWMutex
}
any accidental or intentional assignment/copy of a struct value will create a new mutex, but the underlying map m will be the same (because maps are essentially pointers). As a result, it will be possible to modify/access the map concurrently without locking. Of course, if you strictly follow a rule "thou shalt not copy a set", that won't happen, but it doesn't make much sense to me.
TL;DR: definitely the second way.

How to implement a singleton

I want to implement a singleton with Go. The difference between normal singleton is the instance is singleton with different key in map struct. Something like this code. I am not sure is there any data race with the demo code.
var instanceLock sync.Mutex
var instances map[string]string
func getDemoInstance(key string) string {
if value, ok := instances[key]; ok {
return value
}
instanceLock.Lock()
defer instanceLock.Unlock()
if value, ok := instances[key]; ok {
return value
} else {
instances[key] = key + key
return key + key
}
}
Yes, there is data race, you can confirm by running it with go run -race main.go. If one goroutine locks and modifies the map, another goroutine may be reading it before the lock.
You may use sync.RWMutex to read-lock when just reading it (multiple readers are allowed without blocking each other).
For example:
var (
instancesMU sync.RWMutex
instances = map[string]string{}
)
func getDemoInstance(key string) string {
instancesMU.RLock()
if value, ok := instances[key]; ok {
instancesMU.RUnlock()
return value
}
instancesMU.RUnlock()
instancesMU.Lock()
defer instancesMU.Unlock()
if value, ok := instances[key]; ok {
return value
}
value := key + key
instances[key] = value
return value
}
You can try this as well: sync.Map
Map is like a Go map[interface{}]interface{} but is safe for concurrent use by multiple goroutines without additional locking or coordination. Loads, stores, and deletes run in amortized constant time.
The Map type is optimized for two common use cases: (1) when the entry for a given key is only ever written once but read many times, as in caches that only grow, or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys.
In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.
Note: In the third paragraph it mentions why using sync.Map is beneficial rather than using Go Map simply paired up with sync.RWMutex.
So this perfectly fits your case, I guess?
Little late to answer, anyways this should help: https://github.com/ashwinshirva/api/tree/master/dp/singleton
This shows two ways to implement singleton:
Using the sync.Mutex
Using sync.Once

Why is this map empty when I populate it in a Goroutine?

type driver struct {
variables map[string]string
}
var Drivers []driver
func main() {
driver := driver{
variables: make(map[string]string),
}
Drivers = append(Drivers, driver)
driver.variables = make(map[string]string) // Commenting this line makes it work, too
done := make(chan bool)
go driver.populate(done)
<-done
fmt.Print(Drivers[0].variables)
}
func (this *driver) populate(done chan bool) {
time.Sleep(500 * time.Millisecond)
this.variables["a"] = "b"
done <- true
}
I expected:
map[a:b]
Actual result:
map[]
Playground
The problem is simple: you have a slice of drivers:
var Drivers []driver
Note that Drivers is a slice of some struct type, not a slice of pointers!
When you append something (or you assign a value to one of its elements):
Drivers = append(Drivers, driver)
That makes a copy of the value appended (or assigned)! So when you do this later:
driver.variables = make(map[string]string)
It will set a new map value to driver.variables, but that is distinct from the value stored in Drivers (more precisely at Drivers[0]).
Later you populate driver.variables, but you print Drivers[0].variables. They are 2 different struct values, with 2 different map values. Goroutines do not play a role here (they are properly synchronized so they shouldn't anyway).
Would you print driver.variables:
fmt.Print(driver.variables)
You would see (try it on the Go Playground):
map[a:b]
If you comment out this line:
driver.variables = make(map[string]string) // Commenting this line makes it work, too
It would work, but only because even though you have 2 struct values, they have the same map value (same map header pointing to the same map data structure).
You can also make it work if you call driver.populate() on the struct value Drivers[0] (and sticking to printing Drivers[0].variables):
go Drivers[0].populate(done)
// ...
fmt.Print(Drivers[0].variables)
Try this one on the Go Playground.
And you can also make it work if Drivers is a slice of pointers:
var Drivers []*driver
// ...
driver := &driver{
variables: make(map[string]string),
}
Because driver and Driver[0] will be the same pointer (you will have only one struct value and one map value as the initial map is not accessible anymore). Try this on the Go Playground.
The reason why using the goroutine version you are not getting an uninitialized map is that when the main function returns, the program exits: it does not wait for other (non-main) goroutines to complete. Please be aware the main function itself is a goroutine.
So even if you initialize the map using:
driver.variables = make(map[string]string)
it does not mean that you actually populate with values, you are only initialize a hash map data structure and returns a map value that points to it.
Map types are reference types, like pointers or slices, and so the
value of m above is nil; it doesn't point to an initialized map. A nil
map behaves like an empty map when reading, but attempts to write to a
nil map will cause a runtime panic; don't do that. To initialize a
map, use the built in make function.
In case you remove the go keyword first it will initialize the driver.variables map. But because it's running in the same thread (the main thread) and you put a time delay on the populate function first it will initialize the map, then populate it.
I'd better use channels instead of sleeps:
package main
import (
"fmt"
"time"
)
type driver struct {
variables map[string]string
}
var Drivers []driver
func main() {
driver := driver{
variables: make(map[string]string),
}
Drivers = append(Drivers, driver)
done := make(chan bool)
go driver.populate(done)
<-done // wait for goroutine to complete
fmt.Print(Drivers[0].variables)
}
func (this *driver) populate(done chan bool) {
time.Sleep(500 * time.Millisecond)
this.variables["a"] = "b"
done <- true
}
Playground

Why a slice []struct doesn't behave same as []builtin?

The slices are references to the underlying array. This makes sense and seems to work on builtin/primitive types but why is not working on structs? I assume that even if I update a struct field the reference/address is still the same.
package main
import "fmt"
type My struct {
Name string
}
func main() {
x := []int{1}
update2(x)
fmt.Println(x[0])
update(x)
fmt.Println(x[0])
my := My{Name: ""}
update3([]My{my})
// Why my[0].Name is not "many" ?
fmt.Println(my)
}
func update(x []int) {
x[0] = 999
return
}
func update2(x []int) {
x[0] = 1000
return
}
func update3(x []My) {
x[0].Name = "many"
return
}
To clarify: I'm aware that I could use pointers for both cases. I'm only intrigued why the struct is not updated (unlike the int).
What you do when calling update3 is you pass a new array, containing copies of the value, and you immediately discard the array. This is different from what you do with the primitive, as you keep the array.
There are two approaches here.
1) use an array of pointers instead of an array of values:
You could define update3 like this:
func update3(x []*My) {
x[0].Name = "many"
return
}
and call it using
update3([]*My{&my})
2) write in the array (in the same way you deal with the primitive)
arr := make([]My,1)
arr[0] = My{Name: ""}
update3(arr)
From the GO FAQ:
As in all languages in the C family, everything in Go is passed by
value. That is, a function always gets a copy of the thing being
passed, as if there were an assignment statement assigning the value
to the parameter. For instance, passing an int value to a function
makes a copy of the int, and passing a pointer value makes a copy of
the pointer, but not the data it points to. (See the next section for
a discussion of how this affects method receivers.)
Map and slice values behave like pointers: they are descriptors that
contain pointers to the underlying map or slice data. Copying a map or
slice value doesn't copy the data it points to.
Thus when you pass my you are passing a copy of your struct and the calling code won't see any changes made to that copy.
To have the function change the data in teh struct you have to pass a pointer to the struct.
Your third test is not the same as the first two. Look at this (Playground). In this case, you do not need to use pointers as you are not modifying the slice itself. You are modifying an element of the underlying array. If you wanted to modify the slice, by for instance, appending a new element, you would need to use a pointer to pass the slice by reference. Notice that I changed the prints to display the type as well as the value.

Thread Safe In Value Receiver In Go

type MyMap struct {
data map[int]int
}
func (m Mymap)foo(){
//insert or read from m.data
}
...
go func f (m *Mymap){
for {
//insert into m.data
}
}()
...
Var m Mymap
m.foo()
When I call m.foo(), as we know , there is a copy of "m",value copy ,which is done by compiler 。 My question is , is there a race in the procedure? It is some kind of reading data from the var "m", I mean , you may need a read lock in case someone is inserting values into m.data when you are copying something from m.data.
If it is thread-safe , is it guarenteed by compiler?
This is not safe, and there is no implied safe concurrent access in the language. All concurrent data access is unsafe, and needs to be protected with channels or locks.
Because maps internally contain references to the data they contain, even as the outer structure is copied the map still points to the same data. A concurrent map is often a common requirement, and all you need to do is add a mutex to protect the reads and writes. Though a Mutex pointer would work with your value receiver, it's more idiomatic to use a pointer receiver for mutating methods.
type MyMap struct {
sync.Mutex
data map[int]int
}
func (m *MyMap) foo() {
m.Lock()
defer m.Unlock()
//insert or read from m.data
}
The go memory model is very explicit, and races are generally very easy to reason about. When in doubt, always run your program or tests with -race.

Resources