Ответ
В Go паттерн 'вещание' (broadcast) можно реализовать несколькими способами, каждый со своими особенностями:
-
Закрытие канала (one-time broadcast) Это самый простой способ. При закрытии канала все горутины, ожидающие чтения из него, немедленно разблокируются и получат нулевое значение типа канала.
- Плюсы: Простота реализации.
- Минусы: Это одноразовый сигнал. После закрытия канал нельзя использовать для отправки данных.
broadcastChan := make(chan struct{})
// В подписчиках: go func() { <-broadcastChan fmt.Println("Горутина 1 получила сигнал!") }()
// Вещатель: close(broadcastChan) // Все горутины получат сигнал
-
Рассылка по нескольким каналам (Fan-out) Создается отдельный канал для каждого подписчика, и вещатель отправляет сообщение в каждый из них.
- Плюсы: Позволяет передавать данные, а не только сигналы.
- Минусы: Если один из каналов-получателей не готов принять сообщение (заблокирован), то весь цикл рассылки остановится. Эту проблему можно решить, используя неблокирующую отправку с
select
.// subscribers - это slice или map с каналами подписчиков for _, ch := range subscribers { // Неблокирующая отправка, чтобы не зависнуть на одном подписчике select { case ch <- message: default: // Сообщение будет пропущено, если подписчик не готов } }
-
Использование
sync.Cond
sync.Cond
— это условная переменная, которая позволяет горутинам ждать наступления определенного события. Это более низкоуровневый и производительный механизм для синхронизации.cond.Broadcast()
— пробуждает все ожидающие горутины.cond.Signal()
— пробуждает одну случайную горутину.- Плюсы: Высокая производительность, предназначен специально для таких задач.
var mu sync.Mutex cond := sync.NewCond(&mu)
// Получатель (в горутине): cond.L.Lock() cond.Wait() // Ждет сигнала // ... делает работу cond.L.Unlock()
// Вещатель: cond.Broadcast() // Пробуждает всех
-
Реализация паттерна Pub/Sub Это наиболее полный и гибкий подход. Создается центральный менеджер (в виде горутины), который управляет списком подписчиков (добавление/удаление) и рассылает им сообщения. Обычно это комбинация второго подхода с защитой доступа к списку подписчиков через мьютекс.