跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • go map 并发写的问题
未分類
5 2 月 2021

go map 并发写的问题

go map 并发写的问题

資深大佬 : yujianwjj 6

场景是多个 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 只写不读的场景有什么效率更高的方式。
大佬有話說 (30)

  • 資深大佬 : YUX

    用 sync.Map

  • 資深大佬 : Takamine

    5000 报错,100 不报错就是单纯概率问题吧。

    只写不读可以给 map 包一层方法,在写的地方加锁。

  • 資深大佬 : BeautifulSoap

    因为你 count 5000 的时候触发 map 同时写入的几率非常高啊。。。

    100 一下子就执行完毕了数量也少同时写入几率小

  • 資深大佬 : kiddingU

    @YUX 看主的场景是只写不读,sync.Map 不适合这种场景,锁的粒度太大, 用 concurrent map 就行,或者自己写一个算法,减小锁的粒度

  • 資深大佬 : MidGap

    哈哈哈哈哈好可爱

  • 資深大佬 : JKeita

    我这 10 都报错,可能跟电脑 CPU 性能有关吧,把数据先并发入 chan,再按顺序读取写入 map ?

  • 資深大佬 : monsterxx03

    100 的时候你多试几次就挂了,或者加 -race.
    sync.Map 只对读多写少的场景有效率提升.
    单 map 每次写加锁可能还不如顺序写.
    一般优化思路是做 sharding, 比如预先分配 8 个 map, 每次写的时候 i%8 决定写入哪个 map

  • 資深大佬 : capti0n

    个人理解:
    1.golang 的 map 是 hashmap,会默认分配一部分桶出来,这时并行写入或者访问没问题,
    当超过一定阈值,会触发扩容,这时就会有并发问题。
    2.sync.map 有试过吗?

  • 主 資深大佬 : yujianwjj

    @kiddingU 你说的 concurrent map 是这个吗? https://github.com/orcaman/concurrent-map

  • 資深大佬 : Jooooooooo

    第一个疑问再次说明并发 bug 很难发现.

  • 資深大佬 : kiddingU

    @yujianwjj 是的,也是加锁,只不过是对锁进行了 shard,减轻锁的粒度

  • 資深大佬 : YUX

    @kiddingU 好的 学习了

  • 資深大佬 : cloverstd

    比较好奇

  • 資深大佬 : joesonw

    补充 8 , 这里是学习资料, https://draveness.me/golang/docs/part2-foundation/ch03-datastructure/golang-hashmap/

  • 資深大佬 : nuk

    因为加的越多 hash 冲突就越多,添加一个键花的时间就越久,超过了启动一个 goroutine 的时间,就会报错了。
    用无锁队列然后单线程写好一点吧,写 map 应该不是瓶颈

  • 資深大佬 : ihipop

    @nuk 弄个 chanel 单向灌进去就行吧。。

  • 資深大佬 : nuk

    @ihipop channel 有锁的呀,太多 goroutine 写就不行了

  • 資深大佬 : YouLMAO

    主是只写不读, 必须用 mutex, 连 rwmutex 都不要, 必须比 sync.Map 性能好, 我说的, 性能经过 G 家认证

  • 資深大佬 : raaaaaar

    为什么只写不读?只写的的话那些数据有什么用,是什么业务场景啊

  • 資深大佬 : felixin

    If there is only one lesson I learn from the 30 years experience of network/multi-threading programming, that is NEVER SHARE STATES.

    Pieter Hintjens

  • 資深大佬 : xmge

    1. 概率问题,对共享资源同时操作肯定会报错
    2. 如果是只读不写,只能加锁,sync.map 也不要用,sync.map 底层是读写分离,写时加锁。

  • 資深大佬 : yzbythesea

    chan or mutex lock

  • 資深大佬 : Kinnice

    你电脑性能有点好

  • 主 資深大佬 : yujianwjj

    抱歉,题目描述有误,我的场景是先写后读,先加载大量的数据到 map 里面,后面再查找。

  • 資深大佬 : march1993

    用 goroutine+chan 啊,一个 routine 专门读 chan 然后修改 map,其他 routine 把要修改的内容发到 chan 里

  • 資深大佬 : sunshinev

    sync.Map

  • 資深大佬 : mengdodo

    我记得当初看到过这样一句话:Go 中的 Map 类型不是一种安全的数据类型。所以我比较菜,直接写到 redis 中

  • 資深大佬 : kiddingU

    说用 chan 的,chan 底层数据结构是个啥,有研究过吗~

  • 資深大佬 : Dongxiem

    @kiddingU 这个很难说的清楚的吧?可以看看这个 深度解密 Go 语言之 channel ( https://zhuanlan.zhihu.com/p/74613114 )

  • 資深大佬 : kiddingU

    有啥难说清楚的,看源码不就清楚了~

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具