Назад к урокам

Каналы (Channels) в Go

Урок объясняет, что такое каналы в Go, как передавать данные между горутинами, различия между буферизированными и небуферизированными каналами, работу с select, таймауты и создание однонаправленных каналов.

Начинающий12 min

🔄 Каналы (Channels) в Go

Каналы - это механизм связи между горутинами, позволяющий безопасно передавать данные, синхронизировать выполнение и строить конкурентный код без гонок данных.


📦 Создание канала

ch := make(chan int)

Так создаётся небуферизированный канал, который блокирует отправителя до момента чтения.


📤 Отправка и 📥 приём данных

go func() { ch <- 1 }()
value := <-ch
fmt.Println(value) // 1
  • ch <- x - отправка данных
  • <-ch - получение данных

🔁 Несколько отправителей

ch := make(chan int)

go func() { ch <- 1 }()
go func() { ch <- 2 }()
go func() { ch <- 3 }()

a := <-ch
b := <-ch
c := <-ch

fmt.Println(a, b, c)

Порядок зависит от планировщика.


🧺 Буферизированные каналы

Буфер позволяет отправлять данные без немедленного чтения:

ch := make(chan int, 2)

ch <- 1
ch <- 2

go func() { ch <- 3 }()

fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
fmt.Println(<-ch) // 3

Поведение - FIFO.


🔀 Однонаправленные каналы

Можно ограничить направление:

func worker(in <-chan int, out chan<- int) {
    x := <-in
    out <- x * 2
}
  • <-chan - только чтение
  • chan<- - только запись

🎛 Select: работа с несколькими каналами

select даёт возможность слушать несколько каналов:

one := make(chan int)
two := make(chan int)

for {
    select {
    case o := <-one:
        fmt.Println("one:", o)
    case t := <-two:
        fmt.Println("two:", t)
    default:
        fmt.Println("no data")
        time.Sleep(50 * time.Millisecond)
    }
}

⏳ Таймауты через select + time.After

ch := make(chan int)

for {
    select {
    case v := <-ch:
        fmt.Println("received:", v)
    case <-time.After(300 * time.Millisecond):
        fmt.Println("timed out")
        return
    }
}

📚 Итоги

  • Каналы --- двусторонние трубы для передачи данных
  • Небуферизированные каналы блокируют отправку/получение
  • Буферизированные дают очередь FIFO
  • Select работает с несколькими каналами одновременно
  • Можно делать однонаправленные каналы
  • Через time.After легко задавать таймауты