[БЕЗ_ЗВУКА] А
теперь поговорим про прикладное применение каналов и горутин.
Начнём мы с ускорения работы некоторых запросов путём их распараллеливания.
Например, представьте, что у вас есть страницы статьи,
на которой есть комментарии, и какие-то связанные статьи.
При этом комментарии и статьи, они между собой никак не связаны,
хотя чаще всего они получаются последовательно.
В go вы можете распараллелить эту работу,
внеся тяжёлую операцию в отдельную горутину,
которая будет общаться с вашей программой через канал.
То есть, давайте посмотрим, как это работает на практике.
Смотрите, мы вызывает функцию getComments, которая возвращает нам канал.
После этого мы не начинаем сразу ждать ответ из этого канала,
мы выполняем ещё какую-то работу, например, получаем связанные статьи.
И только после этого дожидаемся результата этого канала.
Получается, что в главной горутине,
функции getPage, мы получили связанные статьи,
при этом параллельно с этим мы получили комментарии.
Давайте посмотрим, как это работает внутри функции getComments():
getComments() возвращает нам канал.
Изначально мы сразу создаём его, после этого запускаем горутину,
куда передаём этот канал, и возвращаем его.
При этом сама работа, сама полезная работа, будет выполняться уже в горутине.
В данном случае это просто Sleep(),
однако ничего не мешает нам добавить туда SQL-запрос, например, и,
когда операция закончится, она в канал запишет результат.
Однако есть один нюанс, который стоит знать при таких операциях.
В случае, если вы используете небуферизированный канал, например,
вот так, то что произойдёт,
если по причине какой-то ошибки, например,
той же ошибки с базой данных, вы вернётесь из функции, например, return?
Вот так.
Что получится?
Получится, что ваша корутина, вот эта,
она пытается записать в канал синхронно,
то есть ожидая с другой стороны чтение, но оттуда уже никто не читает.
И получится утечка горутин и, как следствие, утечка памяти.
Поэтому канал должен быть буферизированным на одно значение.
Что это даёт?
Это даёт нам возможность записать хотя бы одно значение в этот канал, не блокируясь.
Тогда получается, что если вдруг мы не
дошли до функции чтения из этого канала,
то мы запишем туда результат,
функция корректно выполнится, завершится,
а сам канал уже после этого, он уберётся сборщиком мусора,
потому что из него никто не пытается ни читать, никто туда не пишет.
Это очень полезный инструмент в работе,
и позволяет неплохо оптимизировать некоторые операции.