Как решается проблема многопоточности и зависания в приложениях?
Что проверяют
Умеете ли вы находить и предотвращать зависания в конкурентном Go-коде: дедлоки, утечки горутин, бесконечные ожидания сети. Типичный уточняющий вопрос: сервис в проде перестал отвечать, но процесс жив, что будете смотреть первым.
Как отвечать
Разделите причины, у каждой свой инструмент:
- гонки данных: доступ к общему состоянию без синхронизации. Ловятся
go test -raceи сборкой с-raceдля стенда, лечатсяsync.Mutex,sync/atomicили передачей владения через канал; - дедлоки: захват мьютексов в разном порядке, повторный
Lockтого жеsync.Mutex(он не реентерабельный), забытыйUnlock. Спасаютdefer mu.Unlock()сразу послеLockи единый порядок захвата. Рантайм напишетall goroutines are asleep - deadlock!, только если заблокированы вообще все горутины, в сервисе с HTTP-сервером этого не случится; - утечки горутин: горутина навсегда висит на отправке в канал, из которого никто не читает. Правило: у каждой горутины есть понятный способ завершиться, обычно
selectсctx.Done(); - бесконечные ожидания: у
http.Clientпо умолчанию таймаута нет. ЗадавайтеTimeoutу клиента иcontext.WithTimeoutна запрос, а уhttp.ServerвыставляйтеReadHeaderTimeoutиWriteTimeout; - координация:
errgroup.WithContextотменяет остальные задачи при первой ошибке,SetLimitограничивает число одновременных горутин.
Диагностика живого процесса: net/http/pprof и /debug/pprof/goroutine?debug=2 показывают стеки всех горутин с причиной ожидания, SIGQUIT выводит тот же дамп в stderr. Постоянный рост числа горутин на графике почти всегда означает утечку. В тестах их ловит goleak.
Где спотыкаются
Держат мьютекс во время медленной операции: сетевого вызова, time.Sleep, отправки в канал. Параллельный код становится последовательным, а блокировка внутри критической секции легко даёт дедлок.
Считают каналы защитой от всех проблем. Небуферизированный канал без читателя вешает отправителя навсегда, а закрытие канала на стороне читателя приводит к панике у пишущего.
Копируют структуру с sync.Mutex по значению. У копии свой замок, и защита пропадает. Это ловит go vet проверкой copylocks.