Your AI powered learning assistant

Изучаем Golang. Урок №21. Concurrency (3). Nil, Unbuffered, Buffered channels. Deadlock.

Содержание

00:00:00

В этом видеоуроке мы начнем знакомиться с каналами. В этом уроке мы рассмотрим различные аспекты работы каналов.

Определение и назначение каналов

00:00:25

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

Nil`овый канал

00:02:05

В этой главе мы узнаем, как создать новый канал. Это так же просто, как объявить переменную с ключевым словом "channel" и указать тип данных, которые будут передаваться через нее.

len и cap канала

00:02:36

Длина канала относится к количеству элементов, находящихся в данный момент в его буфере. Емкость, с другой стороны, представляет собой размер буфера. Когда мы создаем новый канал, его длина и пропускная способность изначально равны нулю. Это означает, что в буфере нет элементов, с ним не связаны мьютексы или переменные условия.

Запись и чтение из каналов

00:03:25

Для записи и извлечения значений из каналов используется специальный оператор, называемый "look". В зависимости от того, написана ли стрелка слева или справа от канала, ее значение меняется. Например, если стрелка находится с правой стороны канала, это означает, что мы помещаем туда значение. Важная вещь, которую нужно знать об одноканальном устройстве, - это как организовать его запись и извлечение.

Deadlock

00:04:03

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

Закрытие каналов (close)

00:05:13

Процесс закрытия каналов завершился ошибкой. Давайте обсудим следующую операцию, которую можно выполнить с каналами. Каналы могут быть закрыты и дальше, и я объясню, почему это необходимо. А пока позвольте мне привести вам пример, используя неуклюжую аналогию: представьте, что существует специальная функция под названием "Клаус", которая принимает канал в качестве входных данных. В данном случае мы пытаемся закрыть наш канал "melovii". Давайте запустим его и посмотрим, что получится. Как вы можете видеть, мы столкнулись с паникой, потому что новый канал не может быть закрыт, если продолжается анализ его контента. Этот конкретный канал вряд ли когда-нибудь нам пригодится; значения не могут быть записаны или прочитаны из него, как только он закрыт с помощью обычного объявления переменной. Таким образом, по сути, создавая такой канал с помощью обычного объявления переменной, подобного этому (ссылаясь на предыдущий код), вы не получите выгоды от использования каналов.

Небуферизованный канал (unbuffered channel)

00:06:01

Небуферизованный канал Небуферизованный канал - это тип канала, у которого нет буфера. Когда мы создаем небуферизованный канал с помощью функции make, мы указываем тип значения, которое будет передаваться через него. Размер и пропускная способность канала равны нулю, что означает, что буферизация не используется.

Операции "чтения" и "записи" по небуферизованным каналам Операции "чтения" и "записи" в небуферизованном канале требуют одновременного присутствия как считывателя, так и записывающего устройства для обмена данными. Если в данный момент времени нет доступных устройств записи или считывания, операция блокируется до тех пор, пока они не станут доступными.

Обменивайтесь данными по небуферизованным каналам Для обмена данными с небуферизованным каналом вам понадобятся как минимум две подпрограммы: одна для записи (отправитель) и другая для чтения (получатель). И отправитель, и получатель должны пытаться установить связь одновременно, иначе они заблокируют друг друга

Работа с каналом после его закрытия

00:11:45

Работа с закрытыми каналами После закрытия канала важно понять, как он работает. Давайте запустим наш код и посмотрим, что произойдет. Мы сталкиваемся с ошибкой при попытке отправить данные после закрытия канала, потому что нам заблокирована запись в закрытый канал. Кроме того, существует задержка в полсекунды перед закрытием канала с помощью функции "закрыть" и еще одна задержка в полсекунды перед попыткой считывания из закрытого канала. Только в этот момент должна произойти запись, но помните, что как только канал закрыт, больше никаких записей быть не может.

Еще одна важная вещь, которую следует отметить, заключается в том, что если вы попытаетесь снова закрыть уже закрытую chanel, возникнет паника.

Направленность каналов

00:13:24

Каналы могут быть направлены как для записи, так и для чтения. У нас есть два способа создать канал: один предназначен исключительно для записи, а другой - исключительно для чтения. В некоторых случаях нам может потребоваться использовать определенный канал только для записи данных или только для извлечения данных.

Буферизованный канал (buffered channel)

00:15:13

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

Канал "bufere zero van" Каналы "Bufere zero van" аналогичны обычным каналам, но имеют буфер размером 0. Это означает, что они не блокируются при записи до тех пор, пока буфер не заполнится, или при чтении до тех пор, пока буфер не опустеет.

Различия между буферизованными каналами и каналами "bufere zero van" Основное различие между буферизованными каналами и каналами "bufere zero van" заключается в их поведении при записи или чтении данных. Буферизованные каналы допускают многократную запись без блокировки, пока в буфере есть свободное место, в то время как каналы "bufere zero van" допускают только одну запись за раз, поскольку их буферы всегда пусты.

Циклы по каналам

00:20:46

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

Для чего нужно закрывать каналы?

00:23:25

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

Чтение из закрытого канала

00:24:05

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

Проверка на закрытие канала

00:24:42

Чтобы проверить, закрыт ли канал, мы можем использовать значение канала по умолчанию. Считывая значение из канала, мы можем определить, был ли он закрыт или нет. Для этого нам нужны две переменные: одна для хранения текущего значения канала, а другая для указания, открыт он или закрыт. Если мы видим, что наш канал уже закрыт, то мы останавливаем наш цикл и продолжаем нашу программу.

For .. range для итерации по каналам

00:26:24

"Для диапазона" - это удобный способ перебора каналов. Это позволяет нам считывать значения из канала до тех пор, пока он не будет закрыт. Используя "для каждого", мы можем избежать бесконечного считывания значений и гарантировать, что цикл завершается при закрытии канала.

Какой тип каналов использовать?

00:29:05

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

Мы сделали это

00:29:24

Мы разработали программу, которая уменьшит блокировку и повысит скорость. Мы изучили различные теории о каналах, изучили их внутреннюю структуру и обнаружили, как замороженные каналы блокируются, в то время как буферизованные - нет. Это понимание часто отсутствует в учебниках. В следующем видеоуроке мы продолжим изучение каналов и рассмотрим различные варианты использования. Я также покажу вам примеры кода, использующего один и тот же пакет, но с разными методами использования каналов.