Golang sync.Cond
Что такое sync.Cond
?
sync.Cond
в Go — это примитив синхронизации, который позволяет горутинам ожидать или сигнализировать о наступлении определенного события. Он полезен в ситуациях, когда одна или несколько горутин должны ждать, пока другая горутина не выполнит какое-то условие или не изменит состояние.
Основные методы sync.Cond
:
Wait()
— приостанавливает выполнение горутины до тех пор, пока не будет получен сигнал.Signal()
— пробуждает одну горутину, ожидающую на этом условии.Broadcast()
— пробуждает все горутины, ожидающие на этом условии.
Как работает sync.Cond
?
1. Инициализация
sync.Cond
создается с помощью функции sync.NewCond
, которая принимает мьютекс (sync.Mutex
или sync.RWMutex
).
1 2 |
var mu sync.Mutex cond := sync.NewCond(&mu) |
2. Ожидание (Wait
)
Горутина вызывает Wait()
, чтобы приостановить свое выполнение. Внутри Wait()
мьютекс автоматически разблокируется, чтобы другие горутины могли получить доступ к общим данным. Когда горутина получает сигнал (через Signal()
или Broadcast()
), она снова блокирует мьютекс и продолжает выполнение.
3. Сигнализация (Signal
и Broadcast
)
Signal()
пробуждает одну горутину, ожидающую на этом условии.Broadcast()
пробуждает все горутины, ожидающие на этом условии.
Пример использования sync.Cond
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package main import ( "fmt" "sync" "time" ) func main() { var mu sync.Mutex cond := sync.NewCond(&mu) var ready bool // Горутина, которая ждет сигнала go func() { mu.Lock() for !ready { cond.Wait() // Ожидаем, пока ready не станет true } fmt.Println("Горутина: условие выполнено!") mu.Unlock() }() // Имитируем работу time.Sleep(2 * time.Second) // Меняем условие и отправляем сигнал mu.Lock() ready = true cond.Signal() // Пробуждаем одну горутину mu.Unlock() // Даем время для завершения time.Sleep(time.Second) } |
Когда использовать sync.Cond
?
sync.Cond
полезен в следующих сценариях:
- Ожидание изменения состояния: Например, когда одна горутина должна ждать, пока другая горутина не обновит общие данные.
- Координация между горутинами: Например, когда несколько горутин должны ждать, пока главная горутина не выполнит определенное действие.
Основные моменты:
- Мьютекс обязателен:
sync.Cond
всегда работает в связке с мьютексом. Мьютекс защищает общие данные, которые проверяются в условии. - Проверка условия в цикле: После пробуждения горутины из
Wait()
, условие следует проверять снова в цикле, чтобы избежать ложных пробуждений (spurious wakeups). Broadcast()
vsSignal()
: ИспользуйтеBroadcast()
, если нужно пробудить все горутины, иSignal()
, если достаточно пробудить одну.
Пример с Broadcast()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package main import ( "fmt" "sync" "time" ) func main() { var mu sync.Mutex cond := sync.NewCond(&mu) var ready bool // Несколько горутин, ожидающих сигнала for i := 0; i < 5; i++ { go func(id int) { mu.Lock() for !ready { cond.Wait() } fmt.Printf("Горутина %d: условие выполнено!\n", id) mu.Unlock() }(i) } // Имитируем работу time.Sleep(2 * time.Second) // Меняем условие и отправляем сигнал всем mu.Lock() ready = true cond.Broadcast() // Пробуждаем все горутины mu.Unlock() // Даем время для завершения time.Sleep(time.Second) } |
Преимущества sync.Cond
:
- Позволяет эффективно синхронизировать горутины, избегая активного ожидания (busy waiting).
- Упрощает координацию между горутинами, особенно в сложных сценариях.
Альтернативы sync.Cond
:
- Каналы: В Go часто используют каналы для синхронизации горутин. Однако
sync.Cond
может быть более удобным в случаях, когда нужно ждать изменения состояния. sync.WaitGroup
: Подходит для ожидания завершения группы горутин, но не для ожидания изменения состояния.
Итог:
sync.Cond
— это мощный инструмент для синхронизации горутин в Go. Он особенно полезен, когда горутины должны ждать изменения состояния или события. Однако его использование требует аккуратности, чтобы избежать гонок и ложных пробуждений. Если вы работаете с общими данными и условиями, sync.Cond
может стать отличным выбором! 😊
Recommended Posts
Golang map и Swiss Table
16.03.2025