Почему 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
, это будет работать, как вы намерены.