Почему GO паникует с "одновременной записью карты" здесь?

При попытке использовать эту структуру с несколькими программами иногда я получаю одну из следующих ошибок:

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
}

1 ответ

Решение

После прочтения кода на Github, на который вы ссылались, crawl() функция принимает concurrentStorage (не указатель).

Для каждой разыменования (то есть: *urlSet) при звонке crawl()копируете concurrentStorage структура (включая sync.Mutex) пока карта сохраняет указатель на оригинал. Это означает, что ваши мьютексы изолированы от каждой программы, пока они находятся в одном и том же состоянии.

Если вы измените crawl() вместо этого принять указатель и прекратить разыменование concurrentStorage, это будет работать, как вы намерены.

Другие вопросы по тегам