Использование каналов открывает нам возможности по синхронизации между различными горутинами. Например, одна горутина производит некоторое действие, результат которой используется в другой горутине. В этом плане мы можем использовать каналы для синхронизации. Например, одна горутина вычисляет факториал числа, а результат выводится в другой горутине:
package main import "fmt" func main() { intCh := make(chan int) go factorial(5, intCh) fmt.Println(<-intCh) } func factorial(n int, ch chan int){ result := 1 for i:=1; i <= n; i++{ result *= i } ch <- result }
Канал не обязательно должен нести данные, которые представляют некоторый результат, от которого зависит дальнейшее выполнение горутины. Иногда это может быть холостой объект, например, пустая структура, которая необходима только для синхронизации горутин:
package main import "fmt" func main() { results := make(map[int]int) structCh := make(chan struct{}) go factorial(5, structCh, results) <-structCh // ожидаем закрытия канала structCh for i, v := range results{ fmt.Println(i, " - ", v) } } func factorial(n int, ch chan struct{}, results map[int]int){ defer close(ch) // закрываем канал после завершения горутины result := 1 for i:=1; i <= n; i++{ result *= i results[i] = result } }
В данном случае функция factorial по-прежнему вычисляет факториал, но помещает все факториалы чисел от 1 до n в отображение results, где ключи представляют числа, а значения - факториалы чисел.
Канал, через который горутины взаимодействуют, представляет тип chan struct{}
. Причем функция factorial не отправляе конкретные данные в канал, а просто закрывает его после
выполнения всех своих инструкций с помощью вызова defer close(ch)
. После закрытия канала в функции main получает соответствующий сигнал в строке <-structCh
, и
после этого функция main продолжает свою работу.