Для чего используется sync map?



Ответ

Простой ответ на этот вопрос: достаточно частый кейс использования в Go mutex, который защищает данные в map. sync.Map можно рассматривать как map+RWMutex обертку. Но на деле этот ответ не совсем правильный, так как sync.Map решает одну довольно конкретную проблему cache contention. Что же это такое? При использовании sync.RWMutex в случае блокировки на чтение каждая горутина должна обновить поле readerCount, что происходит атомарно. Довольно обще процесс выглядит так:



- ядро процессора обновляет счетчик;



- ядро процессора сбрасывает кэш для этого адреса для всех других ядер;



- ядро процессора объявляет, что только оно знает действующее значение для обрабатываемого адреса;



- следующее ядро процессора вычитывает значение из кэша предыдущего;



- процесс повторяется. Так вот, когда несколько ядер хотят обновить readerCount, образуется очередь. И операция, которую мы считали константной, становится линейной относительно количества ядер. Именно решая эту проблему и ввели sync.Map. sync.Map рекомендуется применять именно на многопроцессорных системах.



// Lock locks rw for writing.

// If the lock is already locked for reading or writing,

// Lock blocks until the lock is available.

func (rw *RWMutex) Lock() {

if race.Enabled {

_ = rw.w.state

race.Disable()

}

// First, resolve competition with other writers.

rw.w.Lock()

// Announce to readers there is a pending writer.

r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders

// Wait for active readers.

if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {

runtime_SemacquireMutex(&rw.writerSem, false, 0)

}

if race.Enabled {

race.Enable()

race.Acquire(unsafe.Pointer(&rw.readerSem))

race.Acquire(unsafe.Pointer(&rw.writerSem))

}

}




@golang_interview