[БЕЗ_ЗВУКА] В этом видео мы поговорим про пакет Context, одна из областей которого является как раз отмена такого рода асинхронных операций. Давайте посмотрим пример. Итак. Допустим, мы отправляем запросы на несколько разных серверов, при этом нам нужен только первый из них, и всех остальных мы не ждём. Можно, конечно, попробовать реализовать ожидания через какой-то канал или ещё что-то, но обычно это делается через как раз Context. Начнём создание. Итак, мы создаём контекст; контекст, который имеет просто функцию отмены. Нам возвращается сам контекст и функция отмены finish. ContextBackground — это такой базовый контекст, от которого обычно всё наследуется. После этого мы запускаем десять воркеров; первым параметром мы им передаём контекст. Контекст всегда передаётся первым парметром практически во все функции, и вы тоже будете это делать, потому что он содержит не только отмену, но и ещё кое-какие другие данные, про которые мы поговорим в другом видео. Но вернёмся к отмене. Итак, мы запускаем воркер в отдельной горутине, куда передаём контекст, номер воркера и канал с результатом. После этого мы дожидаемся первого результата, выводим его на экран и вызываем функцию finish. Finish даёт сигнал, что всё, дальше продолжать не надо. Теперь, каким образом обрабатывается finish, каким образом обрабатывается этот сигнал? Сигнал обрабатывается посредством чтения канала, который возвращает нам функция «метод контекста дан», то есть ctx.Done. Это безопасно использовать между несколькими горутинами. Давайте посмотрим на наш воркер; итак, мы эмулируем работу просто каким-то sleep'ом, пишем, что такой-то воркер будет спать столько-то. Как только подошло время этого воркера, мы запишем результат в канал и скажем, что воркер отработал. Если вдруг нам пришёл сигнал, что нужно закругляться, мы просто выйдем из функции. Итак, давайте это запустим и посмотрим, как оно работает. Отлично. У нас запустилось десять воркеров. Меньше всего ждал девятый — всего десять миллисекунд, вот он. Он отработал первым, записал результат в канал, мы прочитали этот результат — result found by 9 — и отмели всю последующую работу, то есть вызвали функцию finish. Так. Теперь рассмотрим немножко другой пример, когда нам надо не вручную завершить выполнение контекста, а по какому-то таймауту. В этом случае мы можем вызвать функцию у пакета Context WithTimeout, которая также вернёт нам функцию finish, — но я не буду ей пользоваться здесь, поэтому я её пропускаю, — и просто сам контекст. Время ожидания будет 50 миллисекунд. После идёт фактически то же самое. А теперь на функцию «работа». Я буду либо ожидать окончания контекста вот здесь и прерву цикл, либо я буду читать из каналов результат и просто писать его на экран и запоминать, сколько мне пришло результатов. Ну и всё. А функция воркера уже ничем не отличается. Он по-прежнему спит, он по-прежнему обрабатывает ctx.Done для того, чтобы завершить свою функцию, либо пишет результат в канал через определённый промежуток времени. Давайте это запустим. Итак. Вот наши воркеры, они спят определённое время. За это время успели отработать воркеры 2, 7 и 8. Они записали свой номер в канал, я его прочитал и вывел на экран, что мне пришло за этот промежуток времени всего три результата. Поскольку я сплю случайное время, то при следующем запуске программы результат у меня получится немножко другой. Context очень широко используется в Go, вы будете его видеть практически повсеместно, и одно из его основных назначений — это отмена выполнения операции. Поэтому если вам нужно отменить какую-то асинхронную операцию, то Context — это как раз ваш выбор.