a, _ := monitor.ProgressBars[configName].Progress.Load("number")
monitor.ProgressBars[configName].Progress.Store("number", a.(int)+1)
我的理解里,map 只能保证并发读写,但是保证不了 先读后写的自增,需要上锁
m.Lock()
a, _ := monitor.ProgressBars[configName].Progress.Load("number")
monitor.ProgressBars[configName].Progress.Store("number", a.(int)+1)
m.Unlock()
不知道哪种是正解,求前辈指点
1
acehowxx 2022-04-10 21:36:04 +08:00 via Android
我觉得不用加锁。已经都用 sync.map 了还加啥锁。
|
2
wangnimabenma OP @acehowxx #1 刚开始我也感觉不用加锁,但是有个情况没搞清楚。 Load 和 Store 是原子的, +1 操作是非原子的
|
3
acehowxx 2022-04-10 21:55:08 +08:00 via Android
@wangnimabenma 那个 store 是个函数,你+1 后就已经是那个函数的第二个参数了。而且你取出来的 a 也是 map 里值的副本,你改变 a 的值并不会改 map 里的值。
|
4
cloverstd 2022-04-10 22:37:36 +08:00
不加锁是 goroutine 安全的,但不是业务并发安全
number 应该存 *int64 ,然后用 atomic 去自增 |
5
wangnimabenma OP @acehowxx #3
|
6
wangnimabenma OP @acehowxx #3 刚测试了下,sync map 的自增是不能并发安全的
```go m := sync.Map{} m.Store("test", 0) go func() { for true { c,_ := m.Load("test") m.Store("test", c.(int)+1) time.Sleep(1 * time.Second) fmt.Println(c) } }() go func() { for true { c,_ := m.Load("test") m.Store("test", c.(int)+1) time.Sleep(1 * time.Second) fmt.Println(c) } }() go func() { for true { c,_ := m.Load("test") m.Store("test", c.(int)+1) time.Sleep(1 * time.Second) fmt.Println(c) } }() go func() { for true { c,_ := m.Load("test") m.Store("test", c.(int)+1) time.Sleep(1 * time.Second) fmt.Println(c) } }() time.Sleep(30 * time.Second) ``` |
7
wangnimabenma OP @cloverstd #4 感谢,测试了下是这样的
|