Каналы обмена данными
Общий вид взаимодействия через канал
канал <- значение // Блокирующая передача
<-канал // Прием данных и их уничтожение
x := <-канал // Прием и сохранение данных
x, ok := <-канал // Как и выше, плюс проверка - открыт ли канал и имеются ли данные
Замечания
Действуют по принципу FIFO
Создание канала
Создать канал можно с помощью функции make
и объявляются конструкцией chan Тип
:
make(chan Тип) // синхронный канал
make(chan Тип, емкость) // асинхронный (буферизированный) канал
// Пример:
messages := make(chan string, 10) // 10 - размер буфера
// однонаправленные каналы
chan<- Тип // описывает канал, позволяющий только посылать значения
<-chan Тип // описывает канал, позволяющий только принимать значения
Если буфер заполнен, нельзя будет писать в канал, пока не будет извлечен хотя бы один элемент (по умолчанию размер буфера - 0). Канал, в котором буфер имеет нулевой размер, может использоваться для отправки значений, только когда на другом конце канала ожидается прием данных. (Эффекта неблокирующих каналов можно добиться с помощью инструкции select
)
// write to channel
messages <- "Leader"
messages <- "Follower"
// read from channel
message1 := <-messages
message2 := <-messages
Обычно каналы создаются для обеспечения обмена данными между go-подпрограммами. Блокирующее поведение каналов можно использовать для синхронизации.
Закрытие канала
Закрыть канал может только sender, не receiver. Отправка данных в закрытый канал вызовет panic. Каналы работают не так, как файлы: их не обязательно закрывать. Закрывайте, если вам необходимо сообщить получателю, что данных больше не будет (например в цикле через range).
Пример:
c := make(chan int, 10)
x := 1
c <- x
close(c)
Пример
func main() {
questions := make(chan string)
defer close(questions)
answers := createSolver(questions)
defer close(answers)
interact(questions, answers)
}
func createSolver(questions chan string) chan string {
answers := make(chan string)
go func() {
for {
someStr := <-questions
// ...
answers <- someStr
}
}()
return answers
}
select
Оператор select
позволяет горутине ожидать выполнения нескольких коммуникационных операций.
select
блокируется до тех пор, пока не будет запущен один из его вариантов, а затем он выполнит этот case
. Он выбирает один случайным образом, если готовы несколько.
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
Подробнее про этот statement см в разделе Процедурное программированее / Ветвления
.
Last updated