Golang map 读写加锁

Jackey Golang 619 次浏览 没有评论

在 Go 中,map 本身并不是线程安全的。如果在并发环境中对 map 进行读写操作,必须采取适当的同步措施来确保线程安全。

使用 sync.RWMutex

sync.RWMutex 提供了读写锁的功能,允许多个读取操作同时进行,但写入操作会独占锁。这种方式非常适合读多写少的场景。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func NewSafeMap() *SafeMap {
return &SafeMap{
m: make(map[string]int),
}
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.RLock() // 读锁
defer sm.mu.RUnlock() // 确保在函数返回时释放锁
value, exists := sm.m[key]
return value, exists
}
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock() // 写锁
defer sm.mu.Unlock() // 确保在函数返回时释放锁
sm.m[key] = value
}
func (sm *SafeMap) Delete(key string) {
sm.mu.Lock() // 写锁
defer sm.mu.Unlock() // 确保在函数返回时释放锁
delete(sm.m, key)
}
func main() {
sm := NewSafeMap()
sm.Set("apple", 5)
value, exists := sm.Get("apple")
if exists {
fmt.Println("Apple count is:", value)
} else {
fmt.Println("Apple not found in the map")
}
}
type SafeMap struct { mu sync.RWMutex m map[string]int } func NewSafeMap() *SafeMap { return &SafeMap{ m: make(map[string]int), } } func (sm *SafeMap) Get(key string) (int, bool) { sm.mu.RLock() // 读锁 defer sm.mu.RUnlock() // 确保在函数返回时释放锁 value, exists := sm.m[key] return value, exists } func (sm *SafeMap) Set(key string, value int) { sm.mu.Lock() // 写锁 defer sm.mu.Unlock() // 确保在函数返回时释放锁 sm.m[key] = value } func (sm *SafeMap) Delete(key string) { sm.mu.Lock() // 写锁 defer sm.mu.Unlock() // 确保在函数返回时释放锁 delete(sm.m, key) } func main() { sm := NewSafeMap() sm.Set("apple", 5) value, exists := sm.Get("apple") if exists { fmt.Println("Apple count is:", value) } else { fmt.Println("Apple not found in the map") } }
type SafeMap struct {
    mu sync.RWMutex
    m  map[string]int
}

func NewSafeMap() *SafeMap {
    return &SafeMap{
        m: make(map[string]int),
    }
}

func (sm *SafeMap) Get(key string) (int, bool) {
    sm.mu.RLock()         // 读锁
    defer sm.mu.RUnlock() // 确保在函数返回时释放锁
    value, exists := sm.m[key]
    return value, exists
}

func (sm *SafeMap) Set(key string, value int) {
    sm.mu.Lock()         // 写锁
    defer sm.mu.Unlock() // 确保在函数返回时释放锁
    sm.m[key] = value
}

func (sm *SafeMap) Delete(key string) {
    sm.mu.Lock()         // 写锁
    defer sm.mu.Unlock() // 确保在函数返回时释放锁
    delete(sm.m, key)
}

func main() {
    sm := NewSafeMap()
    sm.Set("apple", 5)
    value, exists := sm.Get("apple")
    if exists {
        fmt.Println("Apple count is:", value)
    } else {
        fmt.Println("Apple not found in the map")
    }
}

使用 sync.Map

Go 标准库中的 sync.Map 提供了一种并发安全的 map,它内置了同步机制,适用于需要频繁并发访问的场景。与普通的 map 相比,sync.Map 的一些操作方法有所不同。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
func main() {
var sm sync.Map
// 写入操作
sm.Store("apple", 5)
// 读取操作
value, exists := sm.Load("apple")
if exists {
fmt.Println("Apple count is:", value)
} else {
fmt.Println("Apple not found in the map")
}
// 删除操作
sm.Delete("apple")
// 再次读取,确认删除
value, exists = sm.Load("apple")
if exists {
fmt.Println("Apple count is:", value)
} else {
fmt.Println("Apple not found in the map")
}
}
func main() { var sm sync.Map // 写入操作 sm.Store("apple", 5) // 读取操作 value, exists := sm.Load("apple") if exists { fmt.Println("Apple count is:", value) } else { fmt.Println("Apple not found in the map") } // 删除操作 sm.Delete("apple") // 再次读取,确认删除 value, exists = sm.Load("apple") if exists { fmt.Println("Apple count is:", value) } else { fmt.Println("Apple not found in the map") } }
func main() {
    var sm sync.Map

    // 写入操作
    sm.Store("apple", 5)

    // 读取操作
    value, exists := sm.Load("apple")
    if exists {
        fmt.Println("Apple count is:", value)
    } else {
        fmt.Println("Apple not found in the map")
    }

    // 删除操作
    sm.Delete("apple")

    // 再次读取,确认删除
    value, exists = sm.Load("apple")
    if exists {
        fmt.Println("Apple count is:", value)
    } else {
        fmt.Println("Apple not found in the map")
    }
}

比较 sync.RWMutex 和 sync.Map

  • sync.RWMutex: 适合读多写少的场景,读操作不会相互阻塞。需要手动实现 map 的读写锁逻辑,更灵活,但也更容易出错。
  • sync.Map: 适合读写都频繁的场景,使用简单,内置了并发安全的机制,不需要手动管理锁。但是由于它的内部实现,某些操作可能会比使用普通的 map 加锁的方式慢,特别是在竞争激烈的场景下。

选择哪种方式取决于具体使用场景和性能需求。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Go