> Как определить дедлок в Go и когда он возникает? (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Т-Банк
Стек: Go
> Пример ответа
Дедлок (взаимная блокировка) в Go возникает, когда две или более горутины ожидают освобождения ресурсов, захваченных друг другом, и ни одна из них не может продолжить выполнение. В Go это чаще всего происходит при неправильной работе с мьютексами (sync.Mutex) или каналами.
Как определить дедлок:
- Ручное тестирование и логирование: Добавьте логи до и после блокировок. Если программа зависает без вывода лога после захвата мьютекса - это признак дедлока.
- Использование
go tool trace: Запустите программу с профилированием трассировки (go run -trace trace.out main.go), затем проанализируйтеtrace.outчерезgo tool trace. На временной шкале вы увидите горутины, которые бесконечно ждут блокировок. - Встроенный детектор дедлоков: В Go есть встроенный детектор, который срабатывает при запуске программы с флагом
-race(например,go run -race main.go). Он выявит не только гонки данных, но и некоторые дедлоки, особенно при работе с каналами. - Анализ кода: Ищите циклические зависимости в блокировках. Например, горутина A захватывает mutex1 и ждет mutex2, а горутина B захватывает mutex2 и ждет mutex1.
Когда возникает:
- Взаимные блокировки мьютексов: Две горутины пытаются захватить два мьютекса в разном порядке.
- Ожидание на каналах: Горутина отправляет в канал, который никто не читает, или читает из канала, в который никто не отправляет (если канал небуферизированный).
- Рекурсивные блокировки: Одна горутина повторно захватывает мьютекс без разблокировки (в Go
sync.Mutexнереентерабельный, это вызовет панику, но в некоторых обертках может привести к дедлоку).
Пример:
GOvar mu1, mu2 sync.Mutexfunc goroutineA() {mu1.Lock()time.Sleep(time.Millisecond) // имитация работыmu2.Lock()mu2.Unlock()mu1.Unlock()}func goroutineB() {mu2.Lock()time.Sleep(time.Millisecond)mu1.Lock()mu1.Unlock()mu2.Unlock()}
Если запустить обе горутины, возникнет дедлок: A захватит mu1 и ждет mu2, B захватит mu2 и ждет mu1. Детектор -race или трассировка помогут это обнаружить.
> Похожие задачи по Go
Может ли в SQL-запросе быть инъекция и как ее предотвратить
Почему в канале Go без мьютекса не возникает проблем с конкурентным доступом?
Как растет мапа в Go и что влияет на ее увеличение?
Что такое живая зона памяти в Go?
> Похожие задачи по backend
Может ли в SQL-запросе быть инъекция и как ее предотвратить
Почему в канале Go без мьютекса не возникает проблем с конкурентным доступом?
Как растет мапа в Go и что влияет на ее увеличение?
Что такое живая зона памяти в Go?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью