Что такое GIL в Python, зачем он нужен и как работает
Что проверяют
Понимаете ли вы, почему многопоточность в Python ускоряет не всё подряд, и умеете ли выбрать между потоками и процессами. Ответ «GIL это глобальная блокировка» без следствий засчитывают редко.
Как отвечать
GIL это мьютекс интерпретатора CPython: байт-код Python в один момент времени исполняет только один поток, даже если ядер много.
Зачем он нужен: подсчёт ссылок в CPython не потокобезопасен. Без общей блокировки пришлось бы защищать каждый объект по отдельности, а это медленнее для однопоточного кода, которого большинство. GIL это компромисс в пользу простоты и скорости обычного случая.
Практическое следствие одно, и его надо назвать сразу:
- задачи, упирающиеся в процессор (вычисления, обработка изображений) потоками не ускоряются вовсе, иногда даже замедляются из-за переключений;
- задачи, упирающиеся в ожидание (сеть, диск, база) потоками ускоряются отлично: на времени ожидания GIL отпускается, и другой поток работает.
Отсюда выбор инструмента: threading и asyncio для ожидания, multiprocessing для вычислений (у каждого процесса свой интерпретатор и свой GIL). Тяжёлые библиотеки вроде NumPy тоже отпускают GIL внутри своих C-функций, поэтому считают параллельно.
Где спотыкаются
Говорят, что из-за GIL в Python нет настоящей многопоточности. Потоки настоящие, операционные, ограничение только на одновременное исполнение байт-кода.
Забывают, что GIL это деталь CPython, а не языка: в Jython и IronPython его нет, а в CPython 3.13 появился экспериментальный режим без него.
И путают asyncio с потоками: там вообще один поток, а параллельность достигается переключением на ожидании.