面试题答案
一键面试保证并发读写安全的方法及优缺点
-
使用
sync.Mutex
- 优点:简单直观,适用于大多数场景,性能损耗相对较小,实现容易理解。
- 缺点:粒度较大,同一时间只有一个goroutine能访问map,高并发场景下可能成为性能瓶颈。
-
使用
sync.RWMutex
- 优点:读操作可以并发执行,适用于读多写少的场景,能显著提高性能。
- 缺点:实现相对复杂一些,写操作时会阻止所有读操作,写操作多的场景下可能影响性能。
-
使用
sync.Map
- 优点:专门为高并发场景设计,无需用户手动加锁,自动处理读写冲突,性能较高。
- 缺点:相比
sync.Mutex
和sync.RWMutex
,占用内存更多,不支持遍历(Go 1.9版本之后提供了遍历方法,但使用相对复杂)。
示例代码(使用sync.RWMutex
)
package main
import (
"fmt"
"sync"
)
type UserInfo struct {
Name string
Age int
}
var (
userMap = make(map[string]UserInfo)
rwMutex sync.RWMutex
)
func writeUser(id string, info UserInfo) {
rwMutex.Lock()
defer rwMutex.Unlock()
userMap[id] = info
}
func readUser(id string) (UserInfo, bool) {
rwMutex.RLock()
defer rwMutex.RUnlock()
info, exists := userMap[id]
return info, exists
}
func main() {
var wg sync.WaitGroup
// 模拟写操作
wg.Add(1)
go func() {
defer wg.Done()
writeUser("1", UserInfo{Name: "Alice", Age: 25})
}()
// 模拟读操作
wg.Add(1)
go func() {
defer wg.Done()
info, exists := readUser("1")
if exists {
fmt.Printf("User Info: Name=%s, Age=%d\n", info.Name, info.Age)
} else {
fmt.Println("User not found")
}
}()
wg.Wait()
}
示例代码(使用sync.Map
)
package main
import (
"fmt"
"sync"
)
type UserInfo struct {
Name string
Age int
}
var userSyncMap sync.Map
func writeUser(id string, info UserInfo) {
userSyncMap.Store(id, info)
}
func readUser(id string) (UserInfo, bool) {
value, exists := userSyncMap.Load(id)
if exists {
return value.(UserInfo), true
}
return UserInfo{}, false
}
func main() {
var wg sync.WaitGroup
// 模拟写操作
wg.Add(1)
go func() {
defer wg.Done()
writeUser("1", UserInfo{Name: "Bob", Age: 30})
}()
// 模拟读操作
wg.Add(1)
go func() {
defer wg.Done()
info, exists := readUser("1")
if exists {
fmt.Printf("User Info: Name=%s, Age=%d\n", info.Name, info.Age)
} else {
fmt.Println("User not found")
}
}()
wg.Wait()
}