Ответ
Нет, sync.Mutex
в Go не гарантирует справедливый порядок захвата. Это означает, что горутина, которая дольше всех ждет освобождения мьютекса, не обязательно получит его первой. Такой подход называется "нечестным" (unfair) и выбран в пользу производительности.
Режимы работы sync.Mutex
Начиная с Go 1.9, мьютекс имеет два режима работы для предотвращения полного "голодания" (starvation) горутин:
Нормальный режим (Normal mode): Это режим по умолчанию. Когда мьютекс освобождается, любая горутина — как уже ожидающая, так и только что подошедшая — может попытаться его захватить. Новые горутины имеют преимущество, так как они уже выполняются на процессоре, в то время как ожидающие нужно сначала "разбудить". Это повышает пропускную способность.
Режим голодания (Starvation mode): Если горутина ожидает захвата мьютекса дольше 1 миллисекунды, мьютекс переходит в этот режим. В режиме голодания мьютекс передается строго в порядке очереди — той горутине, которая ждет дольше всех (FIFO). Это снижает производительность, но гарантирует, что ни одна горутина не будет ждать вечно.
Пример
var mu sync.Mutex
func worker(id int) {
mu.Lock()
defer mu.Unlock()
fmt.Printf("Worker %d получил доступn", id)
time.Sleep(10 * time.Millisecond)
}
func main() {
for i := 1; i <= 5; i++ {
go worker(i)
}
time.Sleep(time.Second)
}
Вывод этого кода будет непредсказуемым. Например, Worker 3
может получить доступ раньше Worker 1
, даже если он был запущен позже.
Вывод: Для большинства случаев sync.Mutex
работает эффективно, но если требуется строгий порядок выполнения, лучше использовать каналы.