为什么即使有锁,GO 也会因“并发映射写入”而发生恐慌?

eri*_*mon 1 concurrency mutex go goroutine

当尝试将此结构与多个 goroutine 一起使用时,有时我会收到以下错误之一:

fatal error: concurrent map read and map write

或者

concurrent map writes

读完这篇文章后后,我确保在构造函数中返回一个引用,并将引用传递给接收者。

使用此功能的完整代码位于此 github 存储库中

type concurrentStorage struct {
    sync.Mutex
    domain string
    urls map[url.URL]bool
}

func newConcurrentStorage(d string) *concurrentStorage{
    return &concurrentStorage{
        domain: d,
        urls: map[url.URL]bool{},
    }
}

func (c *concurrentStorage) add(u url.URL) (bool) {
    c.Lock()
    defer c.Unlock()
    if _, ok := c.urls[u]; ok{
        return false
    }
    c.urls[u] = true
    return true
}
Run Code Online (Sandbox Code Playgroud)

Dom*_*nes 6

在阅读您链接到的 Github 上的代码后,该crawl()函数接受 a concurrentStorage(而不是指针)。

*urlSet对于调用时的每个取消引用(即:)crawl(),您将复制concurrentStorage结构(包括sync.Mutex),而映射保留指向原始结构的指针。这意味着您的互斥体与每个 goroutine 是隔离的,同时它们共享相同的状态。

如果您改为crawl()接受指针,并停止取消引用concurrentStorage,它将按您的预期工作。