golang json marshal 锁问题
map操作时,明明已经加了读写锁,为什么还有并发安全问题,以下一个实例,乍一看没有问题,但是运行报错,fatal error:concurrent map read and map write
package main
import (
"encoding/json"
"fmt"
"sync"
)
type obj struct {
wg sync.WaitGroup
mu sync.RWMutex
resMap map[string]int
}
func main() {
obj1 := &obj{
wg: sync.WaitGroup{},
resMap: make(map[string]int),
}
obj1.wg.Add(1000)
for i := 0; i < 500; i++ {
go func(obj1 *obj, i int) {
fmt.Println("write", i)
obj1.set(fmt.Sprintf("%d", i), i)
obj1.wg.Done()
}(obj1, i)
}
for j := 0; j < 500; j++ {
go func(obj1 *obj) {
fmt.Println("read")
res := obj1.get()
json.Marshal(res)
fmt.Println(len(res))
obj1.wg.Done()
}(obj1)
}
obj1.wg.Wait()
}
func (o *obj) get() map[string]int {
o.mu.RLock()
defer o.mu.RUnlock()
return o.resMap
}
func (o *obj) set(key string, val int) {
o.mu.Lock()
defer o.mu.Unlock()
o.resMap[key] = val
}
分析原因:map是引用传递,json.Marshal同样会触发map的读操作,所以会报错
修改后如下,json.Marshal时同样加读锁:
package main
import (
"encoding/json"
"fmt"
"sync"
)
type obj struct {
wg sync.WaitGroup
mu sync.RWMutex
resMap map[string]int
}
func main() {
obj1 := &obj{
wg: sync.WaitGroup{},
resMap: make(map[string]int),
}
obj1.wg.Add(1000)
for i := 0; i < 500; i++ {
go func(obj1 *obj, i int) {
fmt.Println("write", i)
obj1.set(fmt.Sprintf("%d", i), i)
obj1.wg.Done()
}(obj1, i)
}
for j := 0; j < 500; j++ {
go func(obj1 *obj) {
fmt.Println("read")
obj1.mu.RLock()
res := obj1.get()
json.Marshal(res)
obj1.mu.RUnlock()
fmt.Println(len(res))
obj1.wg.Done()
}(obj1)
}
obj1.wg.Wait()
}
func (o *obj) get() map[string]int {
return o.resMap
}
func (o *obj) set(key string, val int) {
o.mu.Lock()
defer o.mu.Unlock()
o.resMap[key] = val
}