面试题答案
一键面试在Go语言中,对Map进行并发读写操作会引发fatal error: concurrent map read and map write
错误。这是因为Go语言的Map不是线程安全的,多个goroutine同时读写会导致数据竞争和未定义行为。
常见的解决方案有:
- 使用
sync.Mutex
:
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
m := make(map[string]int)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
mu.Lock()
m[key] = id
mu.Unlock()
}(i)
}
wg.Wait()
mu.Lock()
fmt.Println(m)
mu.Unlock()
}
通过sync.Mutex
来保护对Map的读写操作,在读写前加锁,读写完成后解锁。
- 使用
sync.RWMutex
:
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.RWMutex
m := make(map[string]int)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
mu.Lock()
m[key] = id
mu.Unlock()
}(i)
}
wg.Wait()
mu.RLock()
fmt.Println(m)
mu.RUnlock()
}
sync.RWMutex
允许多个读操作并发执行,但写操作必须独占。读操作使用RLock
和RUnlock
,写操作使用Lock
和Unlock
。
- 使用
sync.Map
:
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
m.Store(key, id)
}(i)
}
wg.Wait()
m.Range(func(key, value interface{}) bool {
fmt.Printf("key: %v, value: %v\n", key, value)
return true
})
}
sync.Map
是Go 1.9引入的线程安全的Map实现,它提供了Store
、Load
、LoadOrStore
、Delete
和Range
等方法来进行并发安全的操作。