Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nice, go-idiomatic way of using a shared map

Tags:

concurrency

go

Say I had a program with concurrent access to a map, like this:

func getKey(r *http.Request) string { ... }

values := make(map[string]int)

http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
  key := getKey(r)
  fmt.Fprint(w, values[key])
})

http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
  key := getKey(r)
  values[key] = rand.Int()
})

This is bad since map writes are non-atomic. So I could use a read/write mutex

func getKey(r *http.Request) string { ... }

values := make(map[string]int)
var lock sync.RWMutex

http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
  key := getKey(r)
  lock.RLock()
  fmt.Fprint(w, values[key])
  lock.RUnlock()
})

http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
  key := getKey(r)
  lock.Lock()
  values[key] = rand.Int()
  lock.Unlock()
})

Which seems fine except for the fact that we're directly using mutexes and not channels.

What's a more go-idiomatic way of implementing this? Or is this one of those times where a mutex is really all you need?

like image 242
alecbz Avatar asked Aug 12 '13 16:08

alecbz


People also ask

Is Golang map concurrent safe?

It's important to note that maps in go are not safe for concurrent use. Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously.

What is a map in Go?

Maps are used to store data values in key:value pairs. Each element in a map is a key:value pair. A map is an unordered and changeable collection that does not allow duplicates. The length of a map is the number of its elements.

How do maps work in Go?

In Go language, a map is a powerful, ingenious, and versatile data structure. Golang Maps is a collection of unordered pairs of key-value. It is widely used because it provides fast lookups and values that can retrieve, update or delete with the help of keys. It is a reference to a hash table.

How do you create a map in Go?

Go by Example: Maps Maps are Go's built-in associative data type (sometimes called hashes or dicts in other languages). To create an empty map, use the builtin make : make(map[key-type]val-type) . Set key/value pairs using typical name[key] = val syntax. Printing a map with e.g. fmt.


1 Answers

Here's an alternative channel-based approach, using the channel as a mechanism for mutual exclusion:

func getKey(r *http.Request) string { ... }

values_ch := make(chan map[string]int, 1)
values_ch <- make(map[string]int)

http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
  key := getKey(r)
  values := <- values_ch
  fmt.Fprint(w, values[key])
  values_ch <- values
})

http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
  key := getKey(r)
  values := <- values_ch
  values[key] = rand.Int()
  values_ch <- values
})

where we initially put the resource in a shared channel. Then the goroutines can borrow and return that shared resource. However, unlike the solution with RWMutex, multiple readers can block each other.

like image 188
dyoo Avatar answered Oct 12 '22 13:10

dyoo