type IdService struct {
area int64
node int64
apply map[string]*apply
}
map 并发读写会产生数据竞争,但如果 value 是一个指针,只修改指针对象内的元素,还会有数据竞争问题吗?
1
sdrzlyz 2021-11-01 17:04:02 +08:00
不会引发 panic ,但是这个 value 对应的数据,其它 goroutine 读到的不一定是最新的。
map 本身又没有发生增减的情况,这种场景下,你用 map 图了个啥? |
2
JKeita 2021-11-01 17:58:51 +08:00
不会,不关心数据修改顺序性就没啥影响
|
3
sunny352787 2021-11-01 18:01:22 +08:00
牵扯到多线程就用 sync.Map ,不要自己处理,手动加锁的话性能也会慢很多
|
4
bruce0 2021-11-01 19:01:51 +08:00
@sunny352787 sync.Map 这个适用于读多写少的情况,如果是写多读少的话 自己加锁 可能会更高。当然,绝大多数并发 情况下, 无脑 sync.map 就好了
|
5
rrfeng 2021-11-01 19:37:51 +08:00
你这个 map 并没有写操作,所以没问题。
|
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 writes 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 ``` |
7
xmge 2021-11-01 20:01:27 +08:00
看错题了!尴尬
|
8
stach 2021-11-01 20:45:49 +08:00
只修改指针对象内的元素,不会有数据竞争问题 (并发读写竞争), 会有数据错误问题 (并发安全问题).
前者着重于程序是否可以正常 run, 后者着重于数据是否可以准确的在多线程中 share. 只要是在 多线程, 读写场景, 就要考虑加锁, 或者采用原子操作等方式, 来进行 线程间 同步. |
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 打开看看。
|
10
DCjanus 2021-11-02 08:42:18 +08:00 via Android
只修改指针对象内的元素相当于多线程持有一个指针,并一起修改对应对象,每次修改不是原子的话,可能读到的是中间状态,即使修改是原子的,也有可能读到非预期的值。
|
11
zemul OP 了解了,感谢解答!
|