Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map with concurrent access

Tags:

go

map

mutex

People also ask

Are channels and maps safe for concurrent access?

Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously. If you need to read from and write to a map from concurrently executing goroutines, the accesses must be mediated by some kind of synchronization mechanism.

Are maps thread-safe Java?

Maps are naturally one of the most widely style of Java collection. And, importantly, HashMap is not a thread-safe implementation, while Hashtable does provide thread-safety by synchronizing operations. Even though Hashtable is thread safe, it is not very efficient. Another fully synchronized Map, Collections.

How does Go handle concurrency?

In Go, concurrency works through the use of in-built functions known as Goroutines. Goroutines are functions, unique to Go, that run at the same time alongside other code or programs. They're not OS threads, though, they may be considered lightweight threads. Goroutines are deeply integrated with Go's runtime.

How do I copy a map in Golang?

Maps in Go are reference types, so to deep copy the contents of a map, you cannot assign one instance to another. You can do this by creating a new, empty map and then iterating over the old map in a for range loop to assign the appropriate key-value pairs to the new map.


Multiple readers, no writers is okay:

https://groups.google.com/d/msg/golang-nuts/HpLWnGTp-n8/hyUYmnWJqiQJ

One writer, no readers is okay. (Maps wouldn't be much good otherwise.)

Otherwise, if there is at least one writer and at least one more either writer or reader, then all readers and writers must use synchronization to access the map. A mutex works fine for this.


sync.Map has merged to Go master as of April 27, 2017.

This is the concurrent Map we have all been waiting for.

https://github.com/golang/go/blob/master/src/sync/map.go

https://godoc.org/sync#Map


I answered your question in this reddit thread few days ago:

In Go, maps are not thread-safe. Also, data requires locking even for reading if, for example, there could be another goroutine that is writing the same data (concurrently, that is).

Judging by your clarification in the comments, that there are going to be setter functions too, the answer to your question is yes, you will have to protect your reads with a mutex; you can use a RWMutex. For an example you can look at the source of the implementation of a table data structure (uses a map behind the scenes) which I wrote (actually the one linked in the reddit thread).


You could use concurrent-map to handle the concurrency pains for you.

// Create a new map.
map := cmap.NewConcurrentMap()

// Add item to map, adds "bar" under key "foo"
map.Add("foo", "bar")

// Retrieve item from map.
tmp, ok := map.Get("foo")

// Checks if item exists
if ok == true {
    // Map stores items as interface{}, hence we'll have to cast.
    bar := tmp.(string)
}

// Removes item under key "foo"
map.Remove("foo")

if you only have one writer, then you can probably get away with using an atomic Value. The following is adapted from https://golang.org/pkg/sync/atomic/#example_Value_readMostly (the original uses locks to protect writing, so supports multiple writers)

type Map map[string]string
    var m Value
    m.Store(make(Map))

read := func(key string) (val string) { // read from multiple go routines
            m1 := m.Load().(Map)
            return m1[key]
    }

insert := func(key, val string) {  // update from one go routine
            m1 := m.Load().(Map) // load current value of the data structure
            m2 := make(Map)      // create a new map
            for k, v := range m1 {
                    m2[k] = v // copy all data from the current object to the new one
            }
            m2[key] = val // do the update that we need (can delete/add/change)
            m.Store(m2)   // atomically replace the current object with the new one
            // At this point all new readers start working with the new version.
            // The old version will be garbage collected once the existing readers
            // (if any) are done with it.
    }