map 多个协程写同一个key的值时资源竞争

一、map不是线程安全的。原因是其内部实现没有使用锁机制来保护对其的并发读写操作
多个goroutine同时更新map中的同一个键,可能会导致数据竞争和不确定的结果,甚至程序崩溃。
假设两个goroutine同时执行 myMap[“key”] = value1 和 myMap[“key”] = value2,
最终结果是不确定的,可能是 value1 被存储,也可能是 value2 被存储,或者出现更严重的数据损坏

//以下是一个可能导致数据竞争的错误示例:
func testMap() {
	myMap := make(map[int]int)
	var wg sync.WaitGroup
	numGoroutines := 10
	wg.Add(numGoroutines)
	for i := 0; i < numGoroutines; i++ {
		go func(n int) {
			defer wg.Done()
			myMap[n] = n * n
		}(i)
	}
	wg.Wait()
	fmt.Println(myMap)
}

二、解决办法

1、使用sync.Mutex进行加锁保护:通过在读写操作前加锁,读写操作后解锁,确保同一时间只有一个goroutine能操作map

2、使用sync.Map:这是 Go 1.9 引入的并发安全的map,内部使用了锁和原子操作来保证并发安全。

//使用sync.Mutex方案
func testMutexMap() {
	myMap := make(map[int]int)
	var wg sync.WaitGroup
	var lock sync.Mutex
	numGoroutines := 10
	wg.Add(10)
	for i := 0; i < numGoroutines; i++ {
		go func(n int) {
			defer wg.Done()
			lock.Lock()
			myMap[n] = n * n
			lock.Unlock()
		}(i)
	}
	wg.Wait()
	fmt.Println(myMap)
}
//使用sync.map方案
func testSyncMap() {
	var myMap sync.Map
	var wg sync.WaitGroup
	numGoroutines := 10
	wg.Add(10)
	for i := 0; i < numGoroutines; i++ {
		go func(n int) {
			defer wg.Done()
			myMap.Store(n, n*n)

		}(i)
	}
	wg.Wait()
	myMap.Range(func(key, value any) bool {
		fmt.Printf("Key: %v, Value: %v\n", key, value)
		return true
	})
}

Leave a Reply

Your email address will not be published. Required fields are marked *.

*
*

en_USEnglish
Powered by TranslatePress