在金刚标准包中测试sync.Map。同时读和写似乎不安全。怎么了?
测试代码:
package main
import (
"log"
"sync"
)
func main() {
var m sync.Map
m.Store("count", 0)
var wg sync.WaitGroup
for numOfThread := 0; numOfThread < 10; numOfThread++ {
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
value, ok := m.Load("count")
if !ok {
log.Println("load count error")
} else {
v, _ := value.(int)
m.Store("count", v+1)
}
}
}()
}
log.Println("threads starts")
wg.Wait()
value, ok := m.Load("count")
if ok {
v, _ := value.(int)
log.Printf("final count: %d", v)
}
log.Println("all done")
}https://play.golang.org/p/E-pw4iZUceB
结果应该是10000,但得到的是随机数,而不是10000:
2009/11/10 23:00:00 threads starts
2009/11/10 23:00:00 final count: 6696
2009/11/10 23:00:00 all done发布于 2021-03-24 02:33:15
你有一个种族状况:
value, ok := m.Load("count")
...
v, _ := value.(int)
m.Store("count", v+1)上面的读-修改-存储不会保护其他的goroutines做同样的事情,因此其他goroutines执行的一些增量将被忽略。
sync.Map保护对其成员的并发访问。这意味着,对地图的写入不会导致其他人读取不一致的地图。如果你读-修改-写,没有什么能保护其他猩猩在同一时间更新这个值。当您读取-修改-更新时,您需要一个互斥以保护对地图的访问。
发布于 2021-03-24 03:12:20
package main
import (
"log"
"sync"
)
func main() {
var m sync.Map
m.Store("count", 0)
var wg sync.WaitGroup
var mu *sync.Mutex
for numOfThread := 0; numOfThread < 10; numOfThread++ {
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
mu.Lock()
value, ok := m.Load("count")
if !ok {
log.Println("load count error")
} else {
v, _ := value.(int)
m.Store("count", v+1)
}
mu.Unlock()
}
}()
}
log.Println("threads starts")
wg.Wait()
value, ok := m.Load("count")
if ok {
v, _ := value.(int)
log.Printf("final count: %d", v)
}
log.Println("all done")
}读和写操作都是线程安全的,但是您正在尝试一个upsert或read+write操作。它不是线程安全的。修改代码,使其线程安全。
https://stackoverflow.com/questions/66773922
复制相似问题