在Go中并发访问map时,因内置map非线程安全,直接使用会导致数据竞争、panic或行为异常。为确保安全,推荐使用sync.RWMutex或sync.Mutex封装map。sync.RWMutex允许多个读、独占写,适合读多写少场景;sync.Mutex则简单粗暴,读写均互斥,适合读写均衡场景。此外,Go 1.9引入的sync.Map针对读多写少、键集稳定的场景优化,通过双map机制实现高效无锁读,但不支持直接len和range,且频繁写或键变动大时性能可能不如互斥锁方案。因此,多数通用场景仍推荐sync.RWMutex保护的标准map。

在Golang中安全地并发访问和修改一个
map
sync
sync.RWMutex
sync.Mutex
要安全地在Go中并发操作
map
map
sync.RWMutex
sync.Mutex
sync.RWMutex
sync.Mutex
以下是一个使用
sync.RWMutex
map
package main
import (
"fmt"
"sync"
"time"
)
// SafeMap 是一个并发安全的map封装
type SafeMap struct {
mu sync.RWMutex
data map[string]interface{}
}
// NewSafeMap 创建并返回一个新的SafeMap实例
func NewSafeMap() *SafeMap {
return &SafeMap{
data: make(map[string]interface{}),
}
}
// Set 设置键值对
func (sm *SafeMap) Set(key string, value interface{}) {
sm.mu.Lock() // 写入时加写锁
defer sm.mu.Unlock()
sm.data[key] = value
}
// Get 获取键对应的值
func (sm *SafeMap) Get(key string) (interface{}, bool) {
sm.mu.RLock() // 读取时加读锁
defer sm.mu.RUnlock()
val, ok := sm.data[key]
return val, ok
}
// Delete 删除键值对
func (sm *SafeMap) Delete(key string) {
sm.mu.Lock() // 删除时加写锁
defer sm.mu.Unlock()
delete(sm.data, key)
}
// Len 返回map的长度
func (sm *SafeMap) Len() int {
sm.mu.RLock() // 读取长度也需要读锁
defer sm.mu.RUnlock()
return len(sm.data)
}
func main() {
safeMap := NewSafeMap()
// 启动多个goroutine进行写入
for i := 0; i < 10; i++ {
go func(i int) {
key := fmt.Sprintf("key%d", i)
value := fmt.Sprintf("value%d", i*10)
safeMap.Set(key, value)
fmt.Printf("Set: %s = %s\n", key, value)
}(i)
}
// 稍作等待,确保部分写入完成
time.Sleep(100 * time.Millisecond)
// 启动多个goroutine进行读取
for i := 0; i < 15; i++ { // 故意多一些读取goroutine
go func(i int) {
key := fmt.Sprintf("key%d", i%10) // 读取已存在的或不存在的键
val, ok := safeMap.Get(key)
if ok {
fmt.Printf("Get: %s = %v\n", key, val)
} else {
fmt.Printf("Get: %s not found\n", key)
}
}(i)
}
// 稍作等待,确保读写操作完成
time.Sleep(500 * time.Millisecond)
fmt.Printf("Final map length: %d\n", safeMap.Len())
// 尝试删除一个键
safeMap.Delete("key5")
fmt.Println("Deleted key5")
val, ok := safeMap.Get("key5")
fmt.Printf("Get key5 after delete: %v, %t\n", val, ok)
}这几乎是我在Go并发编程中遇到的第一个“坑”。Go的内置
map
map
map
立即学习“go语言免费学习笔记(深入)”;
最常见且最糟糕的结果是程序会直接
panic
fatal error: concurrent map writes
concurrent map reads and writes
panic
map
map
map
sync.Mutex
sync.RWMutex
选择
sync.Mutex
sync.RWMutex
map
Mutex
RWMutex
sync.Mutex
RWMutex
Mutex
sync.RWMutex
RWMutex
Mutex
RWMutex
在我个人的实践中,如果不能确定读写比例,我通常会倾向于先使用
sync.RWMutex
sync.Mutex
Mutex
sync.Map
sync.Map
map
map
sync.Map
map
sync.Map
sync.Map
map
read
dirty
read
dirty
read
dirty
read
dirty
dirty
read
read
dirty
Load
Store
Delete
与传统互斥锁保护的map
sync.Map
Load
RWMutex
map
Load
sync.Map
RWMutex
dirty
Mutex
RWMutex
map
sync.Map
Load
Store
Delete
LoadOrStore
Range
len()
Range
map
len()
for range
sync.Map
map
map
sync.Map
Mutex
RWMutex
map
map
map
len()
for range
总而言之,如果你发现你的应用场景是读多写少,且键的集合变化不大,或者你需要一个可以原子性地“加载或存储”的功能(
LoadOrStore
sync.Map
map
sync.RWMutex
sync.Mutex
map
以上就是如何在Golang中安全地并发访问和修改一个map的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号