在Go中,如果不对map做同步控制,高并发读写时,会出现fatal级别的错误。复现例子:
错误示例
代码语言:javascript复制package rabbit
import (
"fmt"
"testing"
"time"
)
var count = 100000
func Test_NonConcurrentMap(t *testing.T) {
nonCMap := make(map[int]struct{})
go WriteNonCMap(nonCMap)
go ReadNonCMap(nonCMap)
// To see the fatal
time.Sleep(10 * time.Second)
}
func WriteNonCMap(nonCMap map[int]struct{}) {
for index := 0; index < count; index {
nonCMap[index] = struct{}{}
}
}
func ReadNonCMap(nonCMap map[int]struct{}) {
for index := 0; index < count; index {
fmt.Print(nonCMap[index])
}
}
错误结果
测试Test_NonConcurrentMap 函数会报错:fatal error: concurrent map read and map write
image.png
如果恰好没有报错,则可以提升主进程的sleep时间,增大碰撞区间,或增加count的数量,延长碰撞时间。
错误原因
因为这两个程序都是对一个map去访问,当两个协程同时的去访问这个map时,就会发生资源竞争,进而报错。
解决方法
- sync.map
package rabbit
import (
"fmt"
"sync"
"testing"
"time"
)
var count = 100000
func Test_ConcurrentMap(t *testing.T) {
cMap := &sync.Map{}
go WriteCMap(cMap)
go ReadCMap(cMap)
// Never fatal
time.Sleep(10 * time.Second)
}
func WriteCMap(cMap *sync.Map) {
for index := 0; index < count; index {
cMap.Store(index, struct{}{})
}
}
func ReadCMap(cMap *sync.Map) {
for index := 0; index < count; index {
fmt.Print(cMap.Load(index))
}
}
- channel