详尽解析go中的fatal error: concurrent map writes

fatal error: concurrent map writes

问题出现的原因

go中的map不是并发安全的,所以当多个goroutine同时对map执行写操作的时候,就会报刚刚的错误。

示例代码

package main

import (
    "math/rand"
    "time"
)

func init() {
    rand.Seed(time.Now().UnixNano())
}

func main() {
    ConcurrentWrite()
}

func ConcurrentWrite() {
    m := make(map[int]int)

    f := func() {
        k, v := rand.Int()%50, rand.Int()%1000
        m[k] = v
    }
    for i := 0; i < 10; i++ {
        go f()
    }
    time.Sleep(time.Second * 5)
}

上面代码里,我们启动了10个协程对同一个map执行写操作,强制触发并发写。

运行结果

fatal error: concurrent map writes
fatal error: concurrent map writes

go是如何检测到对map的并发写的

那么我们知道发生的原因之后,追本溯源,我们一起来看下go是如果检测到并进行报错的

首先对map的写在源码上映射为 mapassign函数

// Like mapaccess, but allocates a slot for the key if it is not present in the map.
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer{
 ...
}

因为在这个函数里面执行写操作,那么panic也是在这里报出来的了。

我们忽略到无关的代码,先force在 concurrent map writes 报错。我们发现有如下代码

...
if h.flags&hashWriting != 0 { // h是指向map,
        throw("concurrent map writes")
}
...
// Set hashWriting after calling t.hasher, since t.hasher may panic,
// in which case we have not actually done a write.
h.flags ^= hashWriting // 位操作,把hasWriting 标志位记为1
...
// do wirte things
...
if h.flags&hashWriting == 0 {
  throw("concurrent map writes")
}
h.flags &^= hashWriting // 清空标志位


可以看到,go是通过标志位实现的。在写之前,先吧标志位置为1,写之后,改为0。并且每次修改之前都会做判断,如果不符合预期,则会报错。

如何避免

  1. 尽量少定义全局map变量
  2. 如果必须定义全局map变量,可以加锁
    1. 优化1.可以采用cow策略,read不加锁,每次修改copy修改,再赋值
    2. 优化2.可以采用分片锁,减小锁的粒度
  3. 使用sync.Map
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Go语言中的并发编程 并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很...
    吴佳浩阅读 408评论 0 1
  • "go"的一部分的小技巧,完美的避过了“bug”。可以帮助刚刚入门的小伙伴快速学习python的文章,值得收藏的一...
    璃沫仙人阅读 305评论 0 0
  • 这是一个系列文章,主要分享go的使用建议和技巧,每次分享3点,希望你能有所收获。 1 并发访问map 注释掉加锁和...
    songleo阅读 952评论 0 6
  • Go 语言中的哈希 Map 是江湖上极厉害的一门武功,其入门简单,即便是掌握到了 2、3 层也具有四两拨千斤的神奇...
    唯识相链2阅读 757评论 1 0
  • 推荐指数: 6.0 书籍主旨关键词:特权、焦点、注意力、语言联想、情景联想 观点: 1.统计学现在叫数据分析,社会...
    Jenaral阅读 6,141评论 0 5

友情链接更多精彩内容