package main
import (
"fmt"
"sync"
)
var maps = make(map[int]string,0)
func main() {
var wg sync.WaitGroup
wg.Add(2)
go write_call(1,&wg)
go concurrentRead(1,&wg)
wg.Wait()
}
func write_call(key int,wg *sync.WaitGroup) {
i :=0
var mu sync.Mutex
for{
mu.Lock()
maps[i] = fmt.Sprintf("value%d", i)
mu.Unlock()
i++
}
wg.Done()
}
func concurrentRead(key int,wg *sync.WaitGroup) {
i:=0
var mu sync.Mutex
for{
mu.Lock()
val := maps[i] // 读取操作
fmt.Printf("读取数据:%+v\n",val)
mu.Unlock()
i++
}
}
//我在测试两个协程对一个maps进行读写是否有冲突的,我在读和写的协程里对maps的操作都加锁了,可还是报fatal error: concurrent map read and map write
golang map并发读写加锁仍旧报错
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
3条回答 默认 最新
关注让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。
如果答案能帮助您,请采纳、点赞,非常感谢!
.
每日一句正能量,让它带给您好心情:别让懒惰吞噬你的梦想,行动起来,一切都还来得及。
.根据你的代码分析,问题在于每个goroutine都创建了自己的互斥锁,而不是共享同一个锁。这样实际上并没有实现真正的互斥保护。
问题分析
在你的代码中:
write_call函数创建了自己的sync.MutexconcurrentRead函数也创建了自己的sync.Mutex- 两个锁是独立的,无法相互阻塞
解决方案
方案1:使用全局互斥锁(推荐)
package main import ( "fmt" "sync" ) var maps = make(map[int]string, 0) var mu sync.Mutex // 全局互斥锁 func main() { var wg sync.WaitGroup wg.Add(2) go write_call(1, &wg) go concurrentRead(1, &wg) wg.Wait() } func write_call(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { mu.Lock() maps[i] = fmt.Sprintf("value%d", i) mu.Unlock() i++ } } func concurrentRead(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { mu.Lock() val := maps[i] // 读取操作 fmt.Printf("读取数据:%+v\n", val) mu.Unlock() i++ } }方案2:使用读写锁(更高效)
对于读多写少的场景,使用
sync.RWMutex会更高效:package main import ( "fmt" "sync" ) var maps = make(map[int]string, 0) var rwMu sync.RWMutex // 全局读写锁 func main() { var wg sync.WaitGroup wg.Add(2) go write_call(1, &wg) go concurrentRead(1, &wg) wg.Wait() } func write_call(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { rwMu.Lock() // 写锁 maps[i] = fmt.Sprintf("value%d", i) rwMu.Unlock() i++ } } func concurrentRead(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { rwMu.RLock() // 读锁 val := maps[i] // 读取操作 fmt.Printf("读取数据:%+v\n", val) rwMu.RUnlock() i++ } }方案3:使用 sync.Map(Go 1.9+)
对于并发访问的场景,也可以考虑使用
sync.Map:package main import ( "fmt" "sync" ) var maps sync.Map func main() { var wg sync.WaitGroup wg.Add(2) go write_call(1, &wg) go concurrentRead(1, &wg) wg.Wait() } func write_call(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { maps.Store(i, fmt.Sprintf("value%d", i)) i++ } } func concurrentRead(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { if val, ok := maps.Load(i); ok { fmt.Printf("读取数据:%+v\n", val) } i++ } }关键要点
- 锁必须是共享的:所有需要互斥访问的goroutine必须使用同一个锁实例
- 锁的作用域:锁应该保护需要互斥访问的共享资源
- 读写分离:读多写少时使用读写锁可以提高性能
- 内置解决方案:对于并发map,
sync.Map是专门的设计
你的代码中还有一个问题:无限循环会导致
wg.Done()永远不会执行,可以考虑添加退出条件。本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报