Как решается проблема многопоточности и зависания в приложениях?
Что проверяют
Понимаете ли вы, как устроена конкурентность в Python и откуда берутся зависания: дедлоки на блокировках, заблокированный event loop, потоки, которые нельзя остановить. Следом обычно спрашивают про GIL: раз он есть, нужны ли вообще блокировки.
Как отвечать
Сначала про GIL. В стандартном CPython он не даёт двум потокам одновременно исполнять байткод, но не делает атомарными составные операции: counter += 1 это чтение, сложение и запись, и поток может переключиться между ними. А в free-threaded сборке, официально поддерживаемой с 3.14, GIL нет вовсе.
Причины зависаний и что с ними делать:
- дедлок на
Lock: блокировки берутся в разном порядке или поток повторно берёт свой жеLock. Решения:with lock:, единый порядок захвата,RLockдля реентерабельности,acquire(timeout=...); - бесконечное ожидание:
Queue.get(),Future.result()и запрос черезrequestsпо умолчанию ждут без ограничения. Таймаут у них задаётся явно параметромtimeout; - заблокированный event loop: синхронный вызов внутри корутины (
time.sleep,requests, тяжёлый расчёт) останавливает все задачи. Такое уносят вasyncio.to_threadилиrun_in_executor, а ожидание ограничивают черезasyncio.timeout(); - fork при живых потоках: дочерний процесс получает копию захваченной кем-то блокировки и висит. В 3.14 метод запуска по умолчанию на Linux сменили на
forkserver, но явно заданныйspawnилиforkserverнадёжнее.
Диагностика: py-spy dump --pid показывает стеки всех потоков без остановки процесса, faulthandler.dump_traceback_later() печатает стеки, если программа зависла дольше заданного времени, а режим отладки asyncio пишет в лог колбэки дольше 100 мс.
Где спотыкаются
Думают, что thread.join(timeout=1) прерывает поток. Он только перестаёт ждать, а поток работает дальше. Принудительно остановить поток в Python нельзя, завершение проектируют через threading.Event или флаг.
Лечат зависание event loop увеличением таймаутов, хотя проблема в одном блокирующем вызове, который держит весь цикл.
Отвечают «из-за GIL блокировки не нужны» и получают гонки на составных операциях и на проверке с последующим действием.