go map 并发写的问题

2021-01-25 14:07:39 +08:00
 yujianwjj

场景是多个 goroutine 对一个 map 只写不读。

最开始用加锁的方式,来实现多个 goroutine 对一个 map 进行写入。后来发现效率有点低。就尝试了下不加锁的方式。

func TestMap(t *testing.T) {
	a := map[string]int{}
	count := 100
	wg := sync.WaitGroup{}
	wg.Add(count)
	for i := 0; i < count; i++ {
		go func(i int) {
			a[fmt.Sprintf("%d", i)] = i
			wg.Done()
		}(i)
	}
	wg.Wait()
	for k, v := range a {
		fmt.Println(k, " ", v)
	}
}

以上测试代码能够正常工作,并且写入的数据正确,我就以为 map 只写不读的情况是可以不加锁的。

但是实际场景中 count 为 5000,然后就报错了:

fatal error: concurrent map writes

现在有两个问题:

  1. 为什么 count 为 5000 就报错,100 的时候不报错。
  2. 多个 goroutine 对 map 只写不读的场景有什么效率更高的方式。
6276 次点击
所在节点    Go 编程语言
30 条回复
xmge
2021-01-25 23:59:29 +08:00
1. 概率问题,对共享资源同时操作肯定会报错
2. 如果是只读不写,只能加锁,sync.map 也不要用,sync.map 底层是读写分离,写时加锁。
yzbythesea
2021-01-26 02:49:07 +08:00
chan or mutex lock
Kinnice
2021-01-26 09:53:20 +08:00
你电脑性能有点好
yujianwjj
2021-01-26 10:22:28 +08:00
抱歉,题目描述有误,我的场景是先写后读,先加载大量的数据到 map 里面,后面再查找。
march1993
2021-01-26 11:23:34 +08:00
用 goroutine+chan 啊,一个 routine 专门读 chan 然后修改 map,其他 routine 把要修改的内容发到 chan 里
sunshinev
2021-01-26 11:36:26 +08:00
sync.Map
mengdodo
2021-01-26 15:07:01 +08:00
我记得当初看到过这样一句话:Go 中的 Map 类型不是一种安全的数据类型。所以我比较菜,直接写到 redis 中
kiddingU
2021-01-26 15:58:51 +08:00
说用 chan 的,chan 底层数据结构是个啥,有研究过吗~
Dongxiem
2021-01-27 12:57:09 +08:00
@kiddingU 这个很难说的清楚的吧?可以看看这个 深度解密 Go 语言之 channel ( https://zhuanlan.zhihu.com/p/74613114
kiddingU
2021-01-27 14:14:22 +08:00
有啥难说清楚的,看源码不就清楚了~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/748150

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX