下面的代码有什么问题?
package main
import (
"fmt"
"sync"
)
// 下面的代码有什么问题?
type UserAges struct {
ages map[string]int
sync.Mutex
}
func (ua *UserAges) Add(name string, age int) {
ua.Lock()
defer ua.Unlock()
ua.ages[name] = age
}
func (ua *UserAges) Get(name string) int {
if age, ok := ua.ages[name]; ok {
return age
}
return -1
}
// test
func main() {
ua := &UserAges{ages: make(map[string]int, 0)}
wg := &sync.WaitGroup{}
wg.Add(10 + 4)
// write
for gid := 10000; gid < 10010; gid++ {
go func(gid int, u *UserAges) {
for i := 0; i < 100000; i++ {
name := fmt.Sprintf("gid%d-%d", gid, i)
u.Add(name, i)
}
wg.Done()
}(gid, ua)
}
// read
for gid := 10000; gid < 10004; gid++ {
go func(gid int, u *UserAges) {
for i := 0; i < 100000; i++ {
name := fmt.Sprintf("gid%d-%d", gid, i)
_ = u.Get(name)
}
wg.Done()
}(gid, ua)
}
wg.Wait()
}
请思考,答案和解析在下文
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
答案,会panic
fatal error: concurrent map read and map write
为什么?
// map是并发读写不安全的。map属于引用类型,
// 并发读写时多个协程见是通过指针访问同一个地址,即访问共享变量,此时同时读写资源存在竞争关系。会报错误信息:
// fatal error: concurrent map read and map write
// sync.Mutex 和 sync.RWMutex
//
// Mutex 为互斥锁,Lock() 加锁,Unlock() 解锁
//
// RWMutex 为读写锁,
// 写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占
// 适用于读多写少的场景
如何改写,才能解决并发的问题?
第1种:给读也加上互斥锁
func (ua *UserAges) Get(name string) int {
ua.Lock()
defer ua.Unlock()
if age, ok := ua.ages[name]; ok {
return age
}
return -1
}
第2种,用 sync.RWMutex
改写,适合“多读少写”并发场景
type UserAges struct {
ages map[string]int
sync.RWMutex
}
func (ua *UserAges) Get(name string) int {
ua.Lock()
defer ua.Unlock()
if age, ok := ua.ages[name]; ok {
return age
}
return -1
}