Каналы в Go предназначены для безопасной коммуникации между горутинами и синхронизации параллельных процессов. Они являются фундаментальным механизмом для реализации конкурентных паттернов в Go.
Каналы обеспечивают потокобезопасный обмен информацией без явного использования мьютексов:
ch := make(chan int)
go func() {
ch <- 42 // безопасная передача данных
}()
value := <-ch // безопасное получение
Каналы позволяют координировать выполнение параллельных процессов:
done := make(chan bool)
go func() {
// выполняем работу
done <- true // сигнализируем о завершении
}()
<-done // ожидаем завершения
С помощью каналов удобно реализовывать:
Пример pipeline:
func stage(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * 2
}
close(out)
}()
return out
}
Каналы позволяют корректно останавливать горутины:
stop := make(chan struct{})
go func() {
for {
select {
case <-stop:
return // завершение по сигналу
default:
// работа
}
}
}()
// ...
close(stop) // остановка горутины
Каналы предоставляют высокоуровневую альтернативу мьютексам для защиты общих данных.
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
limiter := time.Tick(200 * time.Millisecond)
for req := range requests {
<-limiter // ограничение скорости
process(req)
}
jobs := make(chan int, 100)
results := make(chan int, 100)
// Запускаем воркеров
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// Отправляем задания
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// Получаем результаты
for a := 1; a <= 9; a++ {
<-results
}
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
case <-time.After(time.Second):
fmt.Println("timeout")
default:
fmt.Println("no messages")
}
Каналы - это не просто фича языка, а философия конкурентного программирования в Go, воплощающая принцип: "Не общайтесь через разделяемую память; вместо этого разделяйте память через общение".