Метод sync.Cond.Broadcast
Метод sync.Cond.Broadcast пробуждает все горутины,
которые ожидают на данном условном объекте. В отличие от
метода Signal, который пробуждает только одну
горутину, Broadcast пробуждает все ожидающие
горутины одновременно. Этот метод используется в ситуациях,
когда изменение состояния затрагивает всех ожидающих,
и все они должны продолжить выполнение.
Синтаксис
c.Broadcast()
Метод не принимает параметров и не возвращает значений.
Он вызывается на экземпляре sync.Cond после
изменения общего состояния, которое ожидают горутины.
Пример
Давайте рассмотрим базовый пример использования
Broadcast для пробуждения всех ожидающих горутин:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
var ready bool
// Запускаем три горутины, которые ожидают сигнала
for i := 1; i <= 3; i++ {
go func(id int) {
mu.Lock()
for !ready {
cond.Wait()
}
fmt.Printf("Goroutine %d: started\n", id)
mu.Unlock()
}(i)
}
// Даем горутинам время начать ожидание
time.Sleep(100 * time.Millisecond)
// Меняем состояние и пробуждаем все горутины
mu.Lock()
ready = true
cond.Broadcast()
mu.Unlock()
// Даем время на вывод результатов
time.Sleep(200 * time.Millisecond)
}
Результат выполнения кода:
"Goroutine 3: started"
"Goroutine 1: started"
"Goroutine 2: started"
В этом примере все три горутины ожидают изменения
переменной ready. После вызова Broadcast
все они пробуждаются и продолжают выполнение.
Порядок вывода может отличаться.
Пример
Давайте сравним поведение Broadcast и Signal
на практическом примере:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
var dataReady bool
var wg sync.WaitGroup
// Запускаем 5 горутин, ожидающих данные
for i := 1; i <= 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
mu.Lock()
for !dataReady {
cond.Wait()
}
fmt.Printf("Worker %d: processing data\n", id)
mu.Unlock()
}(i)
}
time.Sleep(100 * time.Millisecond)
// Подготавливаем данные и пробуждаем всех
mu.Lock()
dataReady = true
fmt.Println("Main: data ready, broadcasting...")
cond.Broadcast()
mu.Unlock()
wg.Wait()
}
Результат выполнения кода:
"Main: data ready, broadcasting..."
"Worker 5: processing data"
"Worker 2: processing data"
"Worker 1: processing data"
"Worker 3: processing data"
"Worker 4: processing data"
В этом примере все пять воркеров ожидают готовности данных.
Использование Broadcast позволяет запустить их всех
одновременно. Если бы мы использовали Signal,
то пробудилась бы только одна горутина.
Пример
Давайте рассмотрим пример с циклическим пробуждением всех горутин на каждом этапе:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
stage := 0
var wg sync.WaitGroup
// Запускаем горутины, ожидающие этапов
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for stage < 3 {
mu.Lock()
for stage == 0 {
cond.Wait()
}
fmt.Printf("Worker %d: stage %d completed\n", id, stage)
mu.Unlock()
}
fmt.Printf("Worker %d: all stages done\n", id)
}(i)
}
// Последовательно проходим этапы
for s := 1; s <= 3; s++ {
time.Sleep(200 * time.Millisecond)
mu.Lock()
stage = s
fmt.Printf("Main: stage %d ready\n", s)
cond.Broadcast()
mu.Unlock()
}
wg.Wait()
}
Результат выполнения кода:
"Main: stage 1 ready"
"Worker 3: stage 1 completed"
"Worker 1: stage 1 completed"
"Worker 2: stage 1 completed"
"Main: stage 2 ready"
"Worker 2: stage 2 completed"
"Worker 1: stage 2 completed"
"Worker 3: stage 2 completed"
"Main: stage 3 ready"
"Worker 3: stage 3 completed"
"Worker 2: stage 3 completed"
"Worker 1: stage 3 completed"
"Worker 1: all stages done"
"Worker 2: all stages done"
"Worker 3: all stages done"
В этом примере Broadcast используется на каждом
этапе для пробуждения всех горутин, которые затем
обрабатывают текущий этап и снова переходят в ожидание.
Смотрите также
-
метод
sync.Cond.Signal,
который пробуждает одну ожидающую горутину -
метод
sync.Cond.Wait,
который переводит горутину в режим ожидания -
структуру
sync.Cond,
которая представляет условную переменную -
метод
sync.NewCond,
который создает новый условный объект