Skip to content

Варианты запроса-ответа

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

Иногда не гарантируется, что на запрос будет возвращено допустимое значение. Вместо этого по разным причинам может быть возвращена ошибка. В таких случаях мы можем использовать тип структуры struct{v T; err error} или пустой тип интерфейса в качестве типа элемента канала.

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

Иногда со стороны ответа может быть возвращена последовательность значений, это своего рода механизм потока данных.

Использование каналов для уведомлений

Уведомления можно рассматривать как специальные запросы/ответы, в которых отвеченные значения не важны. Как правило, мы используем пустой тип структуры struct{} в качестве типов элементов каналов уведомлений, поскольку размер типа struct{} равен нулю, поэтому значения struct{} не потребляют память.

Уведомление 1-к-1 путем отправки значения в канал

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

В следующем примере канал done используется в качестве сигнального канала для уведомлений.

Пришло время поработать с кодом!

Уведомление 1-к-1 путем получения значения из канала

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

Этот способ уведомления используется гораздо реже, чем способ, представленный в последнем примере.

Пришло время поработать с кодом!

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

Уведомления N-to-1 и 1-to-N

Немного расширив приведенные выше два варианта использования, можно легко выполнять уведомления N-to-1 и 1-to-N.

Пришло время поработать с кодом!

Способы выполнения уведомлений 1-к-N и N-к-1, представленные в этом подразделе, на практике обычно не используются. Обычно мы  используем sync.WaitGroup уведомления N-to-1, а уведомления 1-to-N делаем по закрытым каналам. Подробности читай в следующем подразделе.

Широковещательные (от 1 до N) уведомления путем закрытия канала

Способ выполнения уведомлений 1-к-N, показанный в предыдущем разделе, редко используется на практике, поскольку есть способ получше. Используя возможность получения бесконечных значений из закрытого канала, мы можем закрыть канал для широковещательных уведомлений.

В примере из последнего подраздела мы можем заменить три операции отправки канала ready <- struct{}{} в последнем примере одной операцией закрытия канала close(ready) для выполнения уведомлений 1-к-N.

Конечно, мы также можем закрыть канал, чтобы сделать уведомление один к одному. Это наиболее часто используемый способ уведомления в Go.

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