已知多個(gè)goroutine同時(shí)讀寫Map會(huì)出問(wèn)題
如下代碼會(huì)拋出異常
package main
import (
"time"
"fmt"
)
func main() {
c := make(map[string]int)
go func() {//開一個(gè)goroutine寫map
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
go func() { //開一個(gè)goroutine讀map
for j := 0; j < 1000000; j++ {
fmt.Println(c[fmt.Sprintf("%d",j)])
}
}()
time.Sleep(time.Second*20)
}
運(yùn)行結(jié)果
fatal error: concurrent map read and map write
由此可見(jiàn)golang中的map并不是并發(fā)安全的
那么同時(shí)進(jìn)行l(wèi)en、encode俐银、decode链沼、或者同時(shí)write了讨、read的操作呢内颗?
以下進(jìn)行測(cè)試
同時(shí)write和len(正常)
package main
import (
"time"
"fmt"
)
func main() {
c := make(map[string]int)
go func() {//開一個(gè)goroutine寫map
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
go func() { //開一個(gè)goroutine讀map
for j := 0; j < 1000000; j++ {
//fmt.Println(c[fmt.Sprintf("%d",j)])
fmt.Println(len(c))
}
}()
time.Sleep(time.Second*20)
}
運(yùn)行結(jié)果正常钧排,當(dāng)然,同時(shí)read和len也是ok的
同時(shí)write和json.Marshal(異常)
package main
import (
"time"
"fmt"
"encoding/json"
)
func main() {
c := make(map[string]int)
go func() {
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
go func() {
for j := 0; j < 1000000; j++ {
json.Marshal(c)
}
}()
time.Sleep(time.Second*20)
}
運(yùn)行結(jié)果
fatal error: concurrent map iteration and map write
同時(shí)read和json.Unmarshal到同一個(gè)對(duì)象(異常)
package main
import (
"time"
"fmt"
"encoding/json"
)
func main() {
c := make(map[string]int)
for j := 0; j < 100; j++ {
c[fmt.Sprintf("%d", j)] = j
}
b1,_:=json.Marshal(c)
c2 := make(map[string]int)
go func() { //開一個(gè)goroutine讀map
for j := 0; j < 1000000; j++ {
fmt.Println(c2[fmt.Sprintf("%d", j)])
}
}()
go func() { //開一個(gè)goroutine讀map
for j := 0; j < 1000000; j++ {
json.Unmarshal(b1,&c2)
}
}()
time.Sleep(time.Second * 20)
}
運(yùn)行結(jié)果
fatal error: concurrent map read and map write
同時(shí)Read(正常)
package main
import (
"time"
"fmt"
"encoding/json"
)
func main() {
c := make(map[string]int)
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
go func() { //開一個(gè)goroutine讀map
for j := 0; j < 1000000; j++ {
fmt.Println(c[fmt.Sprintf("%d", j)])
}
}()
go func() { //開一個(gè)goroutine讀map
for j := 0; j < 1000000; j++ {
fmt.Println(c[fmt.Sprintf("%d", j)])
}
}()
time.Sleep(time.Second * 20)
}
運(yùn)行結(jié)果正常
同時(shí)Write(異常)
import (
"time"
"fmt"
"encoding/json"
)
func main() {
c := make(map[string]int)
go func() { //開一個(gè)goroutine寫map
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
go func() { //開一個(gè)goroutine寫map
for j := 0; j < 1000000; j++ {
c[fmt.Sprintf("%d", j)] = j
}
}()
time.Sleep(time.Second * 20)
}
運(yùn)行結(jié)果
fatal error: concurrent map writes
結(jié)論:
1.無(wú)論什么情況下len操作總是正常的
2.同時(shí)read不會(huì)引發(fā)異常均澳,同時(shí)read和write會(huì)異常恨溜,同時(shí)write會(huì)異常。
3.read或write的同時(shí)找前,json.Marshall或json.Unmarshall此類解析方法也應(yīng)避免使用糟袁,否則也會(huì)引發(fā)異常。
解決方案很多躺盛,控制同步使用项戴,或者使用鎖,這里就不多說(shuō)了