Ответ
В Go существует два основных подхода к взаимодействию между горутинами, которые отражают философию языка.
1. Каналы (Channels) — Идиоматичный способ
Это предпочтительный и идиоматичный способ в Go, который следует принципу:
"Do not communicate by sharing memory; instead, share memory by communicating."
("Не общайтесь, разделяя память; вместо этого, разделяйте память, общаясь.")
Каналы — это типизированные "трубы", через которые горутины могут безопасно отправлять и получать данные, обеспечивая синхронизацию без явных блокировок.
Пример:
// Создаем канал для передачи целых чисел
ch := make(chan int)
go func() {
// Отправляем данные в канал (операция блокируется, пока кто-то не прочитает)
ch <- 42
}()
// Читаем данные из канала (операция блокируется, пока кто-то не отправит)
value := <-ch
fmt.Println(value) // Выведет: 42Ключевые особенности каналов:
- Буферизация: Каналы могут быть буферизированными (
make(chan int, 10)), что позволяет отправлять несколько значений без немедленной блокировки. - Закрытие: Отправитель может закрыть канал (
close(ch)), чтобы сигнализировать, что данные больше не будут отправляться. - Итерация: Можно итерироваться по каналу с помощью
for range, цикл завершится после закрытия канала. - Мультиплексирование: Оператор
selectпозволяет ожидать данные сразу из нескольких каналов, подобноswitch.
2. Примитивы синхронизации из пакета sync
Этот подход более традиционен для других языков и используется, когда прямое управление состоянием с помощью блокировок более уместно.
sync.Mutexиsync.RWMutex: Используются для защиты доступа к общим данным.Mutexпредоставляет эксклюзивную блокировку, аRWMutexпозволяет множество читателей или одного писателя. Это полезно для защиты критических секций, например, при инкременте общего счетчика.sync.WaitGroup: Позволяет горутине ожидать завершения работы группы других горутин.sync.Once: Гарантирует, что определенный участок кода выполнится только один раз.- Пакет
sync/atomic: Предоставляет низкоуровневые атомарные операции (например,atomic.AddInt64), которые могут быть быстрее мьютексов для простых численных операций.