Какой тип данных наиболее идиоматично и эффективно использовать для канала, который нужен только для сигнализации о событии (например, для синхронизации горутин)?

Ответ

Для сигнализации через каналы, когда не требуется передавать данные, самым идиоматичным и эффективным подходом в Go является использование пустой структуры — struct{}. Таким образом, тип канала будет chan struct{}.

Почему именно chan struct{}?

  1. Эффективность по памяти: Тип struct{} не содержит полей, поэтому переменная этого типа не занимает в памяти места (0 байт). Это самый легковесный тип данных, который можно использовать для сигнала.
  2. Ясность намерения: Использование chan struct{} явно говорит читателю кода, что канал используется исключительно для передачи сигнала, а не для обмена данными. Значение, передаваемое по каналу, не имеет значения — важен сам факт отправки/получения.

Пример: Сигнал о завершении работы

// Используем буферизированный канал, чтобы отправляющая горутина
// не блокировалась, если принимающая сторона еще не готова.
done := make(chan struct{}, 1)

go func() {
    // ... выполняем какую-то полезную работу ...
    fmt.Println("Горутина завершила работу, отправляю сигнал.")

    // Отправляем пустую структуру как сигнал о завершении
    done <- struct{}{}
}()

// Основная горутина блокируется, ожидая сигнала
<-done
fmt.Println("Основная горутина получила сигнал и завершается.")

Сравнение с альтернативами:

  • chan bool: Работает, но менее эффективно. Тип bool занимает 1 байт памяти. Передача значения true или false избыточна, так как сам факт получения данных из канала уже является сигналом.
  • chan int: Еще более избыточен. Занимает 4 или 8 байт (в зависимости от архитектуры) и не несет дополнительной смысловой нагрузки для простой сигнализации.