Каналы
Канал — типизированная «труба», через которую горутины передают друг другу значения.
Оператор <- используется и для отправки, и для получения.
Небуферизованный канал
Отправка блокируется, пока другая горутина не примет значение:
ch := make(chan int)
go func() {
ch <- 42 // отправка
}()
v := <-ch // получение
fmt.Println(v)
Буферизованный канал
Отправка блокируется только когда буфер заполнен:
ch := make(chan string, 2)
ch <- "a"
ch <- "b"
fmt.Println(<-ch, <-ch)
Закрытие и range
func gen(n int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for i := 0; i < n; i++ {
out <- i
}
}()
return out
}
for v := range gen(5) {
fmt.Println(v)
}
Закрывает канал только отправитель. Чтение из закрытого канала возвращает
нулевое значение; проверить состояние можно так: v, ok := <-ch.
select
select ждёт готовности одного из нескольких каналов:
select {
case msg := <-ch1:
fmt.Println("из ch1:", msg)
case msg := <-ch2:
fmt.Println("из ch2:", msg)
case <-time.After(time.Second):
fmt.Println("таймаут")
}
Пул воркеров
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * j
}
}
func main() {
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 <= 5; j++ {
jobs <- j
}
close(jobs)
for i := 0; i < 5; i++ {
fmt.Println(<-results)
}
}
Направленные каналы
chan<- T— только для отправки;<-chan T— только для получения.
Это помогает компилятору ловить ошибки и делает API понятнее.