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编写,并整理提供。
如果答案能帮助您,请采纳、点赞,非常感谢!
.
每日一句正能量,让它带给您好心情:别让懒惰吞噬你的梦想,行动起来,一切都还来得及。
.看到你的代码,我发现了问题所在。虽然你在读写操作中都加了锁,但每个协程使用的是自己独立的互斥锁,这完全失去了锁的保护作用。
问题分析
在你的代码中:
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 提供了专门的
sync.Map:package main import ( "fmt" "sync" ) var syncMap 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 { syncMap.Store(i, fmt.Sprintf("value%d", i)) i++ } } func concurrentRead(key int, wg *sync.WaitGroup) { defer wg.Done() i := 0 for { if val, ok := syncMap.Load(i); ok { fmt.Printf("读取数据:%+v\n", val) } i++ } }关键要点
- 锁必须是共享的:所有需要互斥访问的协程必须使用同一个锁实例
- 注意死锁:确保在函数退出前释放锁(使用
defer) - 性能考虑:根据读写比例选择合适的同步机制
- 无限循环:你的代码中有无限循环,
wg.Done()永远不会执行,需要考虑退出机制
选择哪种方案取决于你的具体需求,对于简单的并发访问,方案1或方案3都是不错的选择。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报