Материал проходит вычитку — возможны неточности.
Урок 68 из 118

Утечки горутин

Следом всплыло второе: клиент отменил загрузку, а её воркер продолжал жить в фоне. Через неделю в метриках «Полки» насчитали сотни забытых горутин. Тикет про утечку повесили на Мишу.

Главная мысль

горутина, которая не может завершиться, — утечка: она держит свой стек вечно; ловят такие утечки сравнением runtime.NumGoroutine до и после работы.

Как горутина утекает

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

<!-- wp:code-run/run {"code":"ch := make(chan int)\ngo func() {\n

Горутина не занимает процессор, пока спит, — но она не завершится никогда. Каждая утёкшая горутина держит свой стек, и под нагрузкой такие утечки складываются в медленно растущую память. Так и росли невидимые воркеры отменённых загрузок в «Полке».

Как ловить

runtime.NumGoroutine возвращает текущее число горутин. Паттерн диагностики простой: запускаешь работу, ждёшь завершения, сравниваешь счётчик до и после:

before := runtime.NumGoroutine()
doWork()
time.Sleep(100 * time.Millisecond) // дать «хвостам» проявиться
after := runtime.NumGoroutine()
fmt.Println("утекло:", after-before)

Если счётчик не вернулся к исходному — кто-то остался висеть.

Почему утечки коварны

Утечка горутины не падает и не видна в профиле CPU — утёкшая горутина спит. Симптомы проявляются косвенно: память потихоньку растёт, а в /debug/pprof/goroutine копится парк «ждущих». Поэтому счётчик горутин — дешёвая метрика, которую стоит держать на графике у любого долгоживущего сервиса. Сергей именно её и вывел на дашборд «Полки» после этого разбора.

Вы узнаете:

  • как утекают через небуферизованные каналы и time.After
  • как горутины правильно ждут ctx.Done()
<!-- wp:course-hub/quiz {"title":"Проверьте себя","questions":[{"text":"Горутина заблокировалась на <-ch, а канал никто не закрывает и не пишет. Что это?","options":[{"text":"Утечка — горутина заблокирована навсегда и держит свой стек","correct":true,"comment":"Она не занимает процессор, но не завершится никогда, и её стек остаётся занятым."},{"text":"Нормальное завершение","correct":false},{"text":"Паника","correct":false},{"text":"Ошибка компиляции","correct":false}]},{"text":"Горутина делает ch

Утёкшая горутина = вечная блокировка = растущая память. Диагностика: runtime.NumGoroutine до/после, метрика на графике.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки