Golang的map并发安全

栏目: Go · 发布时间: 7年前

内容简介:已知多个goroutine同时读写Map会出问题如下代码会抛出异常运行结果

已知多个goroutine同时读写Map会出问题

如下代码会抛出异常

package main
import (
    "time"
    "fmt"
)
func main()  {
    c := make(map[string]int)
    go func() {//开一个goroutine写map
        for j := 0; j < 1000000; j++ {
            c[fmt.Sprintf("%d", j)] = j
        }
    }()
    go func() {    //开一个goroutine读map
        for j := 0; j < 1000000; j++ {
            fmt.Println(c[fmt.Sprintf("%d",j)])
        }
    }()

    time.Sleep(time.Second*20)
}

运行结果

fatal error: concurrent map read and map write

由此可见golang中的map并不是并发安全的

那么同时进行len、encode、decode、或者同时write、read的操作呢?

以下进行测试

同时write和len(正常)

package main

import (
    "time"
    "fmt"
)

func main()  {
    c := make(map[string]int)
    go func() {//开一个goroutine写map
        for j := 0; j < 1000000; j++ {
            c[fmt.Sprintf("%d", j)] = j
        }
    }()
    go func() {    //开一个goroutine读map
        for j := 0; j < 1000000; j++ {
            //fmt.Println(c[fmt.Sprintf("%d",j)])
            fmt.Println(len(c))
        }
    }()

    time.Sleep(time.Second*20)
}

运行结果正常,当然,同时read和len也是ok的

同时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)
}

运行结果

fatal error: concurrent map iteration and map write

同时read和json.Unmarshal到同一个对象(异常)

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() { //开一个goroutine读map
        for j := 0; j < 1000000; j++ {
            fmt.Println(c2[fmt.Sprintf("%d", j)])
        }
    }()
    go func() { //开一个goroutine读map
        for j := 0; j < 1000000; j++ {
            json.Unmarshal(b1,&c2)
        }
    }()
    time.Sleep(time.Second * 20)
}

运行结果

fatal error: concurrent map read and map write

同时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() { //开一个goroutine读map
        for j := 0; j < 1000000; j++ {
            fmt.Println(c[fmt.Sprintf("%d", j)])
        }
    }()
    go func() { //开一个goroutine读map
        for j := 0; j < 1000000; j++ {
            fmt.Println(c[fmt.Sprintf("%d", j)])
        }
    }()
    time.Sleep(time.Second * 20)
}

运行结果正常

同时Write(异常)

import (
    "time"
    "fmt"
    "encoding/json"
)

func main() {
    c := make(map[string]int)
    go func() { //开一个goroutine写map
        for j := 0; j < 1000000; j++ {
            c[fmt.Sprintf("%d", j)] = j
        }
    }()
    go func() { //开一个goroutine写map
        for j := 0; j < 1000000; j++ {
            c[fmt.Sprintf("%d", j)] = j
        }
    }()
    time.Sleep(time.Second * 20)
}

运行结果

fatal error: concurrent map writes

结论:

1.无论什么情况下len操作总是正常的

2.同时read不会引发异常,同时read和write会异常,同时write会异常。

3.read或write的同时,json.Marshall或json.Unmarshall此类解析方法也应避免使用,否则也会引发异常。

解决方案很多,控制同步使用,或者使用锁,这里就不多说了


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Responsive Web Design

Responsive Web Design

Ethan Marcotte / Happy Cog / 2011-6 / USD 18.00

From mobile browsers to netbooks and tablets, users are visiting your sites from an increasing array of devices and browsers. Are your designs ready? Learn how to think beyond the desktop and craft be......一起来看看 《Responsive Web Design》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换