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

Каков контекст?

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

Первый пример собственного контекста

Это простейший контекст, который вы можете создать в go. По сути, он «ловит» контекст, который работает в фоне данной части кода. Это.

Затем во внутренних частях приложения вы можете «прослушать» выполняемый контекст, то есть в каком-то цикле for с оператором select. Проверьте приведенный ниже пример.

Код довольно прост. У нас есть функция Parent, которая делает 4 вещи:

  1. Создает контекст из фона
  2. Создает группу ожидания, используемую для синхронизации основной горутины с вновь созданной.
  3. Выполнение функции Worker в другой горутине

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

Вы, вероятно, думаете о том, как мы можем отправить сигнал Done через контекст. Нет ничего проще, посмотрите пример, это просто расширенная версия предыдущего

Как видите, в функцию Родительский внесены лишь небольшие изменения. Мы изменили контекст по умолчанию на расширенную версию: context.WithCancel. Эта функция возвращает тот же контекст, что и выше, с еще одной функцией, отмена. Отмена может быть вызвана в разных местах, чтобы сигнализировать о состоянии контекста «готово». Мы вызываем его в другой горутине через 500 мс. Затем он остановит выполнение функции Worker.

Контекст в HTTP API

Контекст является частью HTTP-запроса в функциях-обработчиках по умолчанию.

Как видите, вы можете использовать метод r.Context(), чтобы получить текущий контекст запроса и передать его в кроличью нору. Вы можете спросить, почему? Ну, ответ довольно прост, скажем, fetchExistingPosts выполняется около 4 секунд. Вызывающий AddMediumPost не терпит и останавливает запрос через 1 с. Есть еще 3 секунды работы, которую нужно сделать впустую. Вот контекст, в основном функция отмены вызывается всякий раз, когда вызывающий объект AddMediumPost завершается слишком рано, и с учетом сказанного вся работа в fetchExistingPosts также может быть выполнена, а некоторые ресурсы могут быть сохранены для другого задания.

Полезные советы

Почти всегда используйте контекст в функциях/методах

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

func SomeFunction(_ context.Context) ошибка {}

Не передавайте его в поля структуры

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

Вот и все

Спасибо за прочтение. Я хотел передать вам некоторые полезные знания и советы, чтобы упростить вашу работу с вашим кодом golang. Если у вас есть вопросы, задавайте их в комментариях, и я сразу отвечу на них. Увидимся в следующий раз!