What happens if two goroutines concurrently write to the same map

122 阅读1分钟
请注意,本文为作者原创。
Notice that the article is originally created by the author. Please indicate the source when reshipped.

What if two goroutines concurrently write to the same map in golang? let us see a simple example below,

package main

import (
	"strconv"
	"sync"
)

func worker(wg *sync.WaitGroup, m map[string]string) {
	defer wg.Done()

	for i := 0; i < 1000000; i++ {
		m[strconv.Itoa(i)] = strconv.Itoa(i)
	}
}

func main() {
	m := make(map[string]string)
	var wg sync.WaitGroup
	wg.Add(1)
	go worker(&wg, m)

	for i := 0; i < 1000000; i++ {
		m[strconv.Itoa(i)] = strconv.Itoa(i)
	}
	wg.Wait()

}

when run, the code panics with the fatal error below,

fatal error: concurrent map writes

Golang does not allow a map to be written concurrently by mulitple goroutines, if you want to do so, concurrent map is a better choice, or you can add mutex lock before writing to a map concurrently. So the code above may be changed like this,

package main

import (
	"fmt"
	"strconv"
	"sync"
)

func worker(wg *sync.WaitGroup, m map[string]string, mutex *sync.RWMutex) {
	defer wg.Done()
	for i := 0; i < 1000000; i++ {
		mutex.Lock()
		m[strconv.Itoa(i)] = strconv.Itoa(i)
		mutex.Unlock()
	}
}

func main() {
	m := make(map[string]string)
	var wg sync.WaitGroup
	var mutex sync.RWMutex
	wg.Add(1)
	go worker(&wg, m, &mutex)

	for i := 0; i < 1000000; i++ {
		mutex.Lock()
		m[strconv.Itoa(i)] = strconv.Itoa(i)
		mutex.Unlock()
	}
	wg.Wait()

	for k, v := range m {
		fmt.Println(k, v)
	}

}

Or in another way, we can use the open source concurrent map package to implement safe concurrently writing.
Please note, if one goroutine is writing to the map, meanwhile another goroutine is reading the same map, the mutex lock is also needed here to guarantee safely concurrent access.