Есть ли опыт отладки deadlock в синхронном коде
Что проверяют
Был ли у вас реальный случай и умеете ли вы найти зависание инструментами, а не перезапуском процесса. Слово «синхронный» здесь намеренное: речь о потоках, процессах и блокировках в базе, а не об asyncio. Следом просят рассказать, как вы убедились, что это именно deadlock, а не медленный запрос.
Как отвечать
Стройте рассказ из четырёх частей: симптом, диагностика, причина, исправление. Пример и цифры нужны ваши, каркас такой:
- симптом: процесс жив, процессор почти не загружен, запросы висят. Бесконечный цикл, наоборот, грузит процессор;
- диагностика:
py-spy dump --pid <PID>показывает стеки всех потоков работающего процесса без перезапуска. Заранее можно включитьfaulthandler.register(signal.SIGUSR1), и стеки будут печататься по сигналу. По стекам видно, какой поток на какомacquire()стоит; - причина: два потока берут замки A и B в разном порядке. Или поток повторно захватывает обычный
threading.Lock, который нереентерабелен. Или родитель вызываетwait()уsubprocessсstdout=PIPE, а дочерний процесс ждёт, пока освободится заполненный буфер канала. Илиforkв процессе с потоками копирует чужой захваченный замок, например замокlogging; - исправление: единый порядок захвата,
RLockтам, где рекурсия оправдана,communicate()вместоwait(), короткие критические секции без вызова чужого кода под замком.
Если зависание было в базе, скажите, что PostgreSQL находит взаимоблокировку сам через deadlock_timeout (по умолчанию одна секунда) и отменяет одну из транзакций с ошибкой deadlock detected. Лечится это одинаковым порядком обновления строк и повтором транзакции.
Если опыта не было, так и скажите и опишите, как воспроизвели бы проблему на стенде.
Где спотыкаются
Рассказывают шаблонную историю без инструментов. Фраза «посмотрел логи и нашёл причину» не убеждает: логи молчат ровно тогда, когда поток завис.
Лечат таймаутом на acquire() и считают задачу закрытой. Таймаут превращает зависание в редкую ошибку, а циклическое ожидание остаётся.
Думают, что GIL защищает от deadlock. GIL оберегает только внутренности интерпретатора, порядок ваших замков он не контролирует.