понедельник, 16 марта 2020 г.

Каналы в Golang предлагают синхронизированное общение

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

Новое значение канала можно задать с помощью встроенной функции make.

// небуферизованный канал целых чисел
ic := make(chan int)

// буферизованный канал с местом для 10 строк
sc := make(chan string, 10)

Чтобы отправить значение в канал, используйте <- в качестве бинарного оператора. Чтобы получить значение из канала, используйте <- его как унарный оператор.

ic <- 3   // Отправляем 3 по каналу
n := <-sc // Получаем string из канала

Оператор <- указывает направление канала, отправлять или получать. Если направление не указано, канал является двунаправленным.

chan Sushi    // может использоваться для отправки 
              // и получения значений типа Sushi

chan<- string // может использоваться только 
              // для отправки строк

<-chan int    // может использоваться только 
              // для получения целых чисел

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

Если пропускная способность канала равна нулю или отсутствует, канал не буферизуется, и отправитель блокируется, пока получатель не получит значение.

Если у канала есть буфер, отправитель блокируется только до тех пор, пока значение не будет скопировано в буфер; если буфер заполнен, это означает ожидание, пока какой-либо получатель не получит значение.

Приемники всегда блокируются, пока нет данных для приема.

Отправка или получение из нулевого канала блокирует навсегда.

Закрытие канала

Функция close записывает, что больше значений не будет отправлено по каналу. Обратите внимание, что необходимо только закрыть канал, если получатель ищет закрытие.

  • После вызова close и после получения ранее отправленных значений операции приема вернут нулевое значение без блокировки.
  • Многозначная операция приема дополнительно возвращает указание о том, закрыт ли канал.
  • Отправка по закрытому каналу или закрытие закрытого канала вызывает панику во время выполнения. Закрытие нулевого канала также вызывает панику во время выполнения.

ch := make(chan string)
go func() {
    ch <- "Hello!"
    close(ch)
}()

fmt.Println(<-ch) // Печатает "Hello!".
fmt.Println(<-ch) // Печатает нулевое значение строки - "" 
                  // без блокировки.
fmt.Println(<-ch) // Еще раз печатает "".
v, ok := <-ch     // v равно "", ok равно false.

// Получаем значения от ch до закрытия.
for v := range ch {
    fmt.Println(v) // Не будет выполнено.
}

Пример

В следующем примере мы позволяем функции Publish возвращать канал, который используется для трансляции сообщения, когда текст опубликован.

// Publish печатает текст на стандартный вывод 
// по истечении заданного времени.
// Он закрывает канал wait после публикации текста.
func Publish(text string, delay time.Duration) (wait <-chan struct{}) {
    ch := make(chan struct{})
    go func() {
        time.Sleep(delay)
        fmt.Println(text)
        close(ch)
    }()
    return ch
}

Обратите внимание, что мы используем канал с пустыми структурами, чтобы указать, что канал будет использоваться только для сигнализации, а не для передачи данных. Вот как вы можете использовать эту функцию.

wait := Publish("important news", 2 * time.Minute)
// Выполняем еще немного работы.
<-wait // Блокирует, пока текст не будет опубликован.


Читайте также:


Купить gopher

Комментариев нет:

Отправить комментарий