Search code examples
goconcurrencychannel

Is it safe to write to a Golang map concurrently if the keys are always unique?


package main

import (
    "sync"
    "fmt"
)

var m = make(map[string]string)

var seen = make(map[string]bool)

func main() {
    wg := new(sync.WaitGroup)
    wg.Add(1)
    ch := make(chan string)
    go deduplicate(ch, wg)

    toAdd := []string{"foo", "bar", "baz", "foo"}
    for _, s := range toAdd {
        ch <- s
    }
    wg.Wait()
    fmt.Println(m)
}

func deduplicate(ch chan string, wg *sync.WaitGroup) {
    for s := range ch {
        if seen[s] {
            wg.Done()
            continue
        }
        seen[s] = true
        go write(s)
    }
}

func write(s string) {
    m[s] = "written"   
}

Is the code above safe to use? Note that multiple strings will be written to the map m concurrently, but they are sure to be unique values, so no string will be written more than once.


Solution

  • No, that is not safe. It doesn't matter if the keys are unique. You need to avoid concurrent writes or writes concurrent with reads. Concurrent reads are OK.

    You can use the race detector to find problems like this by running go run -race myprog.go. See https://golang.org/doc/articles/race_detector.html.