美文网首页Golang
Golang的map并发安全

Golang的map并发安全

作者: 星落纷纷 | 来源:发表于2019-05-03 03:52 被阅读0次

    已知多个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此类解析方法也应避免使用,否则也会引发异常。

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

    相关文章

      网友评论

        本文标题:Golang的map并发安全

        本文链接:https://www.haomeiwen.com/subject/rdfanqtx.html