gogo-map

Is writing to a mutex map with multiple goroutines faster than one? and why?


I have a SyncMap defined as follow:

type SyncMap struct {
    sync.Mutex
    Map map[int]string
}

And, now I write to it using two ways, one goroutine and multiple goroutines with mutex. codes as follow:

smap := SyncMap{}
smap.Map = make(map[int]string)
t1 := time.Now()
for i := 0; i < 10000; i++ {
    smap.Map[i] = strconv.Itoa(i)
}
elapsed := time.Since(t1)
fmt.Println("t1 elapsed", elapsed)
s2map := SyncMap{}
s2map.Map = make(map[int]string)
t2 := time.Now()
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
    defer wg.Done()
    for i := 0; i < 5000; i++ {
        s2map.Lock()
        s2map.Map[i] = strconv.Itoa(i)
        s2map.Unlock()
    }
}()
go func() {
    defer wg.Done()
    for i := 5000; i < 10000; i++ {
        s2map.Lock()
        s2map.Map[i] = strconv.Itoa(i)
        s2map.Unlock()
    }
}()
wg.Wait()
elapsed2 := time.Since(t2)
fmt.Println("t2 elapsed", elapsed2)

Output as follow:

t1 elapsed 5.0363ms
t2 elapsed 5.9353ms

Try servel time, t1 is always faster than t2. So, my question just as the title says.

Could I understand that's due to the consumption of the mutex lock? The SyncMap in this case or sync.Map in go package is just designed for writing goroutines safe, not for efficiency? And is there some way to promote efficiency when writing map with multiple goroutines?

Thanks~


Solution

  • It's fairly simple. In the second scenario, with the 2 goroutines, because of the mutex, there can be only one of the goroutines writing to the map at one time. So it's really not much different than just doing it sequentially with one goroutine. At any given time only one goroutine will be doing anything. The counters and the looping don't consume much time at all so they can essentially be ignored, it is the map writes that take most of the time.

    However, you also have the additional cost of the lock contention, and the 10,000 lock and unlock operations, which are fairly costly. So that means overall it will be slower.

    In summary, using more goroutines doesn't speed things up if only one goroutine is running at any given time.

    For better efficiency use a better map, like this or this. The map you've created allows no concurrency at all.