В КУРСЕ?

Разбираемся в теме

Горутины в Go: как спроектировать завершение работы

Запустить горутину в Go легко, но надёжная программа должна объяснять и то, как она завершится. Если вызывающая функция уже вернула ответ, а фоновая работа продолжает ждать канал, ресурсы могут оставаться занятыми. Начинать полезно с жизненного цикла: кто запускает задачу, кто сообщает об отмене и кто убеждается, что она действительно остановилась.

Назначьте владельца фоновой работы

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

Отмена является сигналом, а не принудительным убийством

Пакет context передаёт сведения об отмене и сроке выполнения через границы функций. После отмены закрывается канал Done соответствующего контекста. Работающий код должен учитывать этот сигнал: ожидание в select может предусматривать как полезное событие, так и отмену. Сам вызов функции отмены не заставляет произвольный цикл немедленно закончиться. Если библиотека или длительная операция не поддерживает контекст, нужно отдельно изучить доступные способы ограничения её времени. Производные контексты связывают жизненные циклы: отмена родительского распространяется на дочерние. При создании отменяемого контекста также планируют вызов полученной функции отмены для освобождения связанных ресурсов.

Проверьте места возможного ожидания

Типичная проблема возникает, когда получатель перестал читать результаты, а отправитель навсегда ждёт отправки в канал. Буфер иногда откладывает блокировку, но не является универсальным исправлением: число результатов может превысить его вместимость. Продумайте, как отправитель узнает, что данные больше не нужны. Аналогично проверяют ожидание входных данных и завершение сетевых операций. Закрытие канала должно иметь понятного владельца и происходить после завершения всех отправок. Нельзя без согласованного протокола закрывать канал, в который другая горутина ещё пишет. Иначе попытка исправить зависание создаст другую ошибку.

Различайте просьбу остановиться и подтверждение

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

Попробуйте на практике

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

  1. Обозначьте владельца, два рабочих процесса, канал результатов и путь сигнала отмены.
  2. Рассмотрите обычное завершение: кто сообщает, что отправок больше не будет, и кто закрывает канал.
  3. Добавьте ситуацию, когда получатель принимает один результат и больше не читает. Укажите, как разблокируются обе рабочие горутины.
  4. Разделите два события: отмена отправлена и все горутины завершились. Назовите механизм подтверждения второго события.

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

Частые вопросы

Большой буфер канала устраняет утечки горутин?

Не обязательно. Он помогает только при известных ограничениях потока. Если отправок больше, чем свободных мест, проблема ожидания возвращается.

Нужно ли создавать новую горутину для каждой операции?

Нет. Конкурентность должна решать конкретную задачу. Последовательный код часто проще, если параллельное выполнение не даёт полезного выигрыша.

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

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

Зарегистрироваться
← К списку материалов