golang map 并发读写竞争问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
zemul
V2EX    Go 编程语言

golang map 并发读写竞争问题

 
  •   zemul 2021-11-01 16:51:11 +08:00 3174 次点击
    这是一个创建于 1447 天前的主题,其中的信息可能已经有所发展或是发生改变。
    type IdService struct { area int64 node int64 apply map[string]*apply } 

    map 并发读写会产生数据竞争,但如果 value 是一个指针,只修改指针对象内的元素,还会有数据竞争问题吗?

    11 条回复    2021-11-02 21:00:24 +08:00
    sdrzlyz
        1
    sdrzlyz  
       2021-11-01 17:04:02 +08:00
    不会引发 panic ,但是这个 value 对应的数据,其它 goroutine 读到的不一定是最新的。

    map 本身又没有发生增减的情况,这种场景下,你用 map 图了个啥?
    JKeita
        2
    JKeita  
       2021-11-01 17:58:51 +08:00
    不会,不关心数据修改顺序性就没啥影响
    sunny352787
        3
    sunny352787  
       2021-11-01 18:01:22 +08:00
    牵扯到多线程就用 sync.Map ,不要自己处理,手动加锁的话性能也会慢很多
    bruce0
        4
    bruce0  
       2021-11-01 19:01:51 +08:00
    @sunny352787 sync.Map 这个适用于读多写少的情况,如果是写多读少的话 自己加锁 可能会更高。当然,绝大多数并发 情况下, 无脑 sync.map 就好了
    rrfeng
        5
    rrfeng  
       2021-11-01 19:37:51 +08:00
    你这个 map 并没有写操作,所以没问题。
    xmge
        6
    xmge  
       2021-11-01 20:00:29 +08:00
    go map 的并发读写不会 panic ,而是直接调用 throw() 函数,导致程序退出,因此,如果程序中有可能出现 map 并发读写的情况,一定要处理掉,因为这种错误出现时,程序必然挂掉。

    上述的结构是会出现问题的,map 并发读写的检查大概是:当读取某个 key 时会判断一个是否有协程在写的变量,如果有协程在写,则程序退出。

    测试代码:

    ```go
    package main

    import "sync"

    type Person struct {
    Name string
    }

    func main() {
    m := make(map[string]*Person)
    wg := sync.WaitGroup{}
    for i := 0; i < 100; i++ {
    wg.Add(1)
    go func() {
    defer wg.Done()
    for i := 0; i < 1000; i++ {
    m["1"] = new(Person)
    }
    }()
    }
    wg.Wait()
    }
    ```

    报错信息:

    ```
    fatal error: concurrent map rites

    goroutine 21 [running]:
    runtime.throw(0x1076c2d, 0x15)
    /usr/local/go/src/runtime/panic.go:1117 +0x72 fp=0xc00002ff08 sp=0xc00002fed8 pc=0x102dd12
    runtime.mapassign_faststr(0x1068c80, 0xc000098000, 0x1075205, 0x1, 0xc000056088)
    /usr/local/go/src/runtime/map_faststr.go:211 +0x3f1 fp=0xc00002ff70 sp=0xc00002ff08 pc=0x100ea91
    main.main.func1(0xc00009a000, 0xc000098000)
    /Users/maning/go/tmp/hex.go:17 +0xac fp=0xc00002ffd0 sp=0xc00002ff70 pc=0x105f3ec
    runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:1371 +0x1 fp=0xc00002ffd8 sp=0xc00002ffd0 pc=0x105bb81
    created by main.main
    /Users/maning/go/tmp/hex.go:14 +0x91

    ```
    xmge
        7
    xmge  
       2021-11-01 20:01:27 +08:00
    看错题了!尴尬
    stach
        8
    stach  
       2021-11-01 20:45:49 +08:00
    只修改指针对象内的元素,不会有数据竞争问题 (并发读写竞争), 会有数据错误问题 (并发安全问题).
    前者着重于程序是否可以正常 run, 后者着重于数据是否可以准确的在多线程中 share.

    只要是在 多线程, 读写场景, 就要考虑加锁, 或者采用原子操作等方式, 来进行 线程间 同步.
    bazingaterry
        9
    bazingaterry  
       2021-11-01 21:18:55 +08:00
    「修改指针对象内的元素」这里的 map 不存在 data race ,但其他地方不好说。例如指针并发读写请用 https://pkg.go.dev/sync/atomic#Value ,其他拿不准的情况把 https://golang.org/doc/articles/race_detector 打开看看。
    DCjanus
        10
    DCjanus  
       2021-11-02 08:42:18 +08:00 via Android
    只修改指针对象内的元素相当于多线程持有一个指针,并一起修改对应对象,每次修改不是原子的话,可能读到的是中间状态,即使修改是原子的,也有可能读到非预期的值。
    zemul
        11
    zemul  
    OP
       2021-11-02 21:00:24 +08:00
    了解了,感谢解答!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana   span class="snow">   872 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:30 PVG 05:30 LAX 14:30 JFK 17:30
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86