Мьютекс гораздо более комплексная структура по сравнению с atomic, чем может показаться на первый взгляд. Прежде всего у нас есть два вида мютексов:
sync.Mutex
и sync.RWMutex
. У каждого из них есть методы Lock
и Unlock
, у RWMutex
есть дополнительно метод RLock
(блокирование для чтения). В обоих типах методы Lock
довольно долгие по сравнению с атомиками.У
Mutex
код метода Lock
включает два вида блокировки. Первый вариант - это когда удается захватить не заблокированный мьютекс, второй вариант довольно долгий и он запускается если мьютекс заблокирован:// Lock locks m.
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available.
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return
}
// Slow path (outlined so that the fast path can be inlined)
m.lockSlow()
}
Первый вариант довольно быстрый и включает в себя одну
atomic
операцию. Второй вариант включает довольно много кода и здесь подробно разбираться не будет: там также используются атомики в процессе блокировки, но очевидно, что он исполняется еще дольше первого варианта (Fast path).У
RWMutex
код метода Lock
включает в себя вызов метода Lock
структуры Mutex
:// 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()
// Здесь пропущена часть кода ...
}
}
Да и сама структура
RWMutex
включает в себя структуру Mutex
как одно из полей:
type RWMutex struct {
w Mutex // held if there are pending writers
// Здесь пропущена часть кода ...
}
Метод
RLock
у RWMutex
гораздо быстрее и содержит меньше кода, но тем не менее не быстрее атомика, который там задействован:
func (rw *RWMutex) RLock() {
// Здесь пропущена часть кода ...
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// A writer is pending, wait for it.
runtime_SemacquireMutex(&rw.readerSem, false, 0)
}
//
📌Вопрос что производительнее атомики или мьютексы?
Напишите свой ответ в комментариях👇
@golang_interview