> Как определить дедлок в Go и когда он возникает? (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Т-Банк

Стек: Go

> Пример ответа

Дедлок (взаимная блокировка) в Go возникает, когда две или более горутины ожидают освобождения ресурсов, захваченных друг другом, и ни одна из них не может продолжить выполнение. В Go это чаще всего происходит при неправильной работе с мьютексами (sync.Mutex) или каналами.

Как определить дедлок:

  1. Ручное тестирование и логирование: Добавьте логи до и после блокировок. Если программа зависает без вывода лога после захвата мьютекса - это признак дедлока.
  2. Использование go tool trace: Запустите программу с профилированием трассировки (go run -trace trace.out main.go), затем проанализируйте trace.out через go tool trace. На временной шкале вы увидите горутины, которые бесконечно ждут блокировок.
  3. Встроенный детектор дедлоков: В Go есть встроенный детектор, который срабатывает при запуске программы с флагом -race (например, go run -race main.go). Он выявит не только гонки данных, но и некоторые дедлоки, особенно при работе с каналами.
  4. Анализ кода: Ищите циклические зависимости в блокировках. Например, горутина A захватывает mutex1 и ждет mutex2, а горутина B захватывает mutex2 и ждет mutex1.

Когда возникает:

  • Взаимные блокировки мьютексов: Две горутины пытаются захватить два мьютекса в разном порядке.
  • Ожидание на каналах: Горутина отправляет в канал, который никто не читает, или читает из канала, в который никто не отправляет (если канал небуферизированный).
  • Рекурсивные блокировки: Одна горутина повторно захватывает мьютекс без разблокировки (в Go sync.Mutex нереентерабельный, это вызовет панику, но в некоторых обертках может привести к дедлоку).

Пример:

GO
var mu1, mu2 sync.Mutex
func 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 или трассировка помогут это обнаружить.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью