Ответ
Канал (channel) в Go — инструмент коммуникации между горутинами. Канал имеет определённый тип значений, например int, который он может передавать из одной горутины в другую.
Каналы бывают буферизированые и небуферезированные. Для создания канала лучше всего использовать функцию make.
Пример создания небуферизированного канала
ch:=make(chan int)
В go каналы являются указателями.
Для записи и чтения в канал используется синтаксис <-
В этом примере мы передаём данные в канал.
ch <- data
А здесь мы считываем данные из канала
<- ch
Эта операция не сохраняет данные в переменную и она является корректной. Если вам необходимо сохранить данные с канала в переменную, вы можете использовать следующий синтаксис:
data:= <-ch
Все вышеобозначенные операции с каналом являются блокируемыми. Когда вы помещаете данные в канал, горутина блокируется до тех пор, пока данные не будут считаны другой горутиной из этого канала.
В случае небуферизированного канала работает строгая синхронизация между отправителем и получателем:
Если у канала есть получатель, то горутина, которая выполняет чтение из канала <-ch), блокируется до тех пор, пока какая-то другая горутина не запишет данные в этот канал.
И наоборот, если у канала есть отправитель, то горутина, которая выполняет запись в канал ch <- data), блокируется до тех пор, пока какая-то другая горутина не прочитает данные.
Таким образом, операция записи и операция чтения должны произойти одновременно, чтобы обе горутины продолжили выполнение.
Так же канал бывает буферизированным
Чтобы создать буферизированный канал, нужно написать
ch:=make(chan int, 3)
Поведение буферизированных каналов:
1.Запись: Не блокируется пока в буфере есть свободное место. Блокируется когда буфер полный.
2.Чтение: Не блокируется пока в буфере есть данные. Блокируется когда буфер пустой.
3.FIFO порядок: Значения читаются в том же порядке, в котором были записаны (First In, First Out).
Когда буфер полный, отправитель блокируется. Когда буфер пустой, получатель блокируется
Каналы так же бывают однонаправленными и двунаправленными.
Однонаправленный канал
Канал можно создать только для отправки
sender:=make(chan <- int)
и только для получения
receive := make(<- chan int)
Deadlock (Взаимная блокировка)
Чтение или запись данных в канал блокирует горутину и контроль передается свободной горутине. Представим, что такие горутины отсутствуют, либо они все "спят". В этот момент возникает deadlock, который приведет к аварийному завершению программы..
В Go runtime сам обнаруживает deadlock и аварийно завершает программу.
Причины возникновения Deadlock
1. Горутина ожидает данные из канала, но никто их туда не отправляет.
2. Горутина отправляет данные в канал, но никто их не читает.
3. Все горутины заблокированы на операциях с каналами и не могут «разбудить» друг друга.
Закрытие канала
Чтобы горутина не ожидала данных из канала, канал можно закрыть.
close(ch)
Только горутина-отправитель должна закрывать канал, горутина-получатель никогда не должна закрывать канал, так отправка в закрытый канал вызовет панику.
Чтобы проверить закрытие канала в горутине-получателе можно написать
value,ok:=<-ch
ok возвращает false, если больше нет значений для получения и канал закрыт.
Цикл for i := range ch многократно получает значения из канала, пока он не будет закрыт.
Закрывать канал следует, когда больше не будет отправок. Это предотвращает зависания получателей при чтении из канала.
Select
Select оператор, который позволяет одновременно обрабатывать несколько операций, связанных с каналами. Она блокирует выполнение до тех пор, пока одна из операций на одном из каналов не станет доступной для выполнения (чтение или запись), после чего выполняет соответствующий блок кода
bufferedChan := make(chan string, 1)
bufferedChan <- "first"l
select {
case str := <- bufferedChan:
fmt.Println( a: "read", str)
case bufferedChan <- "second":
fmt.Println( a: "write", <- bufferedChan, <- bufferedChan)
}
Select различает три типа операций
1.Блокирующая
2.Неблокирующая
3.default
Select отдаёт приоритет неблокирующим операциям
Если несколько операций являются неблокирующими, то он выбирается случайную
Далее если все операции блокирующие то приоритет отдаётся default
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶