golang,go,博客,开源,编程
sync.Map
是 Go 标准库 sync
包中的一个并发安全的映射(map)类型。它是为了解决普通 map
在多 goroutine 并发访问时的竞态问题而设计的。sync.Map
提供了更高效的并发操作,避免了显式使用锁(如 sync.Mutex
)来保护 map
的访问。
sync.Map
支持并发读写,保证多 goroutine 同时对 map
的读写操作不会发生竞态条件。atomic
操作来提高性能,尤其是对读操作比较频繁的场景,它的性能通常优于使用显式锁的 map
。map
不同,sync.Map
不支持使用普通的下标方式来进行访问(即 syncMap[key]
不可用)。你需要使用专门的 API 来进行操作。sync.Map
的主要方法sync.Map
提供了以下几个方法:
Store(key, value)
:存储一个键值对。Load(key)
:读取一个值,如果键存在,返回该值和 true
,否则返回 nil
和 false
。LoadOrStore(key, value)
:如果键不存在,则将 key
和 value
存储在 map
中,并返回该值。如果键已经存在,则返回该键的现有值和 true
。Delete(key)
:删除指定的键值对。Range(f func(key, value interface{}) bool)
:遍历所有键值对,调用传入的函数。如果函数返回 false
,遍历停止。package main
import (
"fmt"
"sync"
)
func main() {
// 创建一个 sync.Map 实例
var m sync.Map
// 使用 Store 存储数据
m.Store("name", "John")
m.Store("age", 30)
// 使用 Load 读取数据
name, ok := m.Load("name")
if ok {
fmt.Println("Name:", name)
} else {
fmt.Println("Name not found")
}
// 使用 LoadOrStore,存在则返回现有值,不存在则存储
age, _ := m.LoadOrStore("age", 25)
fmt.Println("Age:", age)
// 删除一个键
m.Delete("age")
// 再次检查 age 键
age, ok = m.Load("age")
if ok {
fmt.Println("Age:", age)
} else {
fmt.Println("Age not found")
}
// 使用 Range 遍历所有键值对
m.Store("city", "New York")
m.Range(func(key, value interface{}) bool {
fmt.Printf("%s: %v\n", key, value)
return true // 返回 true 继续遍历
})
}
Name: John
Age: 30
Age not found
city: New York
name: John
Store(key, value)
Store
方法用来向 sync.Map
存储一个键值对。例如,m.Store("name", "John")
将键 "name"
和对应的值 "John"
存入 sync.Map
中。Load(key)
Load
方法用来读取键对应的值。如果键存在,返回该值以及一个布尔值 true
;如果键不存在,则返回 nil
和 false
。例如,name, ok := m.Load("name")
。LoadOrStore(key, value)
LoadOrStore
方法首先检查键是否存在。如果存在,返回现有的值;如果不存在,存储给定的键值对并返回新值。与 Load
和 Store
不同,LoadOrStore
可以在读取时对不存在的键执行存储操作。例如,age, _ := m.LoadOrStore("age", 25)
如果 "age"
不存在,则存储并返回值 25
。Delete(key)
Delete
方法用来删除指定的键。例如,m.Delete("age")
将删除键 "age"
及其对应的值。Range(f func(key, value interface{}) bool)
Range
方法遍历 sync.Map
中的所有键值对,并为每个键值对调用传入的函数 f
。该函数接受两个参数:key
和 value
,并返回一个布尔值。如果返回 false
,则停止遍历;如果返回 true
,则继续遍历。sync.Map
适用于以下场景:
sync.Map
的性能优势尤其明显。sync.Map
常被用作并发安全的缓存容器,特别是在不频繁变动的键值对场景中。sync.Mutex
)来同步访问时,sync.Map
是一个理想的选择。sync.Map
性能不如普通的 map
加锁操作。在写多读少的场景下,使用普通的 map
和 sync.Mutex
或 sync.RWMutex
可能会更高效。sync.Map
对键值对的生命周期没有特殊要求,可以在并发情况下安全地进行添加、删除和查询操作,但不支持直接对 map
进行迭代(需要通过 Range
方法)。sync.Map
的操作是基于 interface{}
类型的,因此,你需要在取出数据时进行类型断言。虽然它提供了灵活性,但也会带来一定的类型安全风险。在使用时,要确保类型断言正确。sync.Map
是 Go 提供的并发安全的映射类型,适用于读多写少的场景。Load
、Store
、LoadOrStore
和 Delete
。Range
方法提供了遍历功能,适用于并发场景下的共享数据存储。如果你的应用场景中有大量的并发访问共享数据,特别是读多写少的情况,sync.Map
是一个非常好的选择。