GIL в Python на собеседовании
Ответ «GIL мешает многопоточности» засчитывают редко: дальше спрашивают, когда он отпускается. Разбираем границу между CPU-bound и I/O-bound задачами.
«GIL мешает многопоточности» — формула верная и почти бесполезная: из неё не следует ни когда потоки всё-таки помогают, ни почему в коде всё равно нужны блокировки. Обе границы описаны в документации одной-двумя строками, и ниже разобраны именно они, а не устройство интерпретатора.
Всё, что сказано о поведении, относится к CPython и к Python 3.13, где это оговорено отдельно.
Что такое GIL и зачем он нужен
Определение из словаря языка стоит держать близко к дословному, потому что в нём три важные детали сразу: GIL — механизм интерпретатора CPython, который гарантирует, что только один поток исполняет байткод Python в каждый момент времени.
Первая деталь — привязка к реализации. Это не свойство языка: другая реализация вправе устроить всё иначе, и оговорка «в CPython» — часть точного ответа, а не педантизм.
Вторая — цель, и она объясняет, почему механизм вообще существует. Блокировка делает объектную модель интерпретатора — включая критичные встроенные типы вроде dict — неявно безопасной при конкурентном доступе. То есть GIL решает задачу разработчиков интерпретатора, а не задачу прикладного программиста.
Третья — цена, названная в том же абзаце столь же прямо: блокировка всего интерпретатора упрощает его многопоточность ценой значительной части параллелизма, который дают многопроцессорные машины. Такая формулировка удобна тем, что не требует оценок: это размен, зафиксированный в документации.
Когда GIL отпускается
Здесь лежит главный факт темы, и он записан в словаре одной фразой: GIL всегда отпускается при вводе-выводе. Из неё выводится вся практическая часть разговора.
Пока поток ждёт ответа от сети, диска или базы данных, блокировку он не держит — значит, другие потоки в это время исполняют байткод. Отсюда правило, которое стоит уметь сформулировать самому: на задачах, где время уходит на ожидание, потоки дают настоящий выигрыш; на задачах, где время уходит на вычисления, — не дают, потому что вычисление и есть исполнение байткода, а исполняет его в каждый момент только один поток.
Это и есть граница, которую обычно называют разделением на I/O-bound и CPU-bound. Ценность её не в терминах, а в том, что она выводится из одной строки документации, а не запоминается как рекомендация.
Есть и вторая, менее известная половина того же абзаца: расширения — стандартные и сторонние — могут отпускать GIL на вычислительно тяжёлых задачах, и словарь называет примеры: сжатие и хеширование. Практическое следствие важное: «CPU-bound значит потоки бесполезны» — упрощение. Если тяжёлая работа выполняется внутри расширения, которое отпускает блокировку, потоки могут дать выигрыш и на вычислениях.
Для случая, когда вычисления идут на чистом Python, остаются процессы: у каждого свой интерпретатор и, значит, свой GIL.
Почему GIL не отменяет блокировок
Из определения следует вывод, который на первый взгляд противоречит здравому смыслу: GIL не делает ваш код потокобезопасным. Безопасной он делает объектную модель интерпретатора — то, что встроенные типы не развалятся от одновременного доступа. Инварианты прикладного кода в эту гарантию не входят.
Механизм расхождения проще всего увидеть на составной операции. Увеличение счётчика — это чтение, сложение и запись. Каждый из трёх шагов выполняется под блокировкой, но между ними блокировка может перейти к другому потоку: он прочитает то же значение, прибавит и запишет — и одно из двух увеличений потеряется. Список при этом не повредится, словарь не сломается — испортится только ваш инвариант, за который GIL и не отвечал.
Отсюда практический вывод: там, где нужна атомарность последовательности действий, нужна явная блокировка. GIL защищает структуры интерпретатора, а не смысл вашей операции.
Что изменилось с версии 3.13
Утверждение «GIL отключить нельзя» было верным долго и перестало им быть недавно — а материалы, написанные до изменения, продолжают лежать в выдаче рядом с новыми. Поправка короткая, и знать её стоит хотя бы для того, чтобы не повторить устаревшее.
Начиная с Python 3.13 GIL можно отключить: для этого существует конфигурация сборки --disable-gil, а собранный так интерпретатор запускается с -X gil=0 либо при установленной переменной окружения PYTHON_GIL=0.
Важно немедленно добавить вторую половину, иначе поправка превратится в новую неточность. PEP 703, вводящий эту возможность, формулирует статус-кво прямо: GIL остаётся значением по умолчанию для сборок CPython и для загрузок с python.org. Это отдельная конфигурация сборки, а не новое поведение языка.
Стоит назвать и цену, потому что она объясняет, почему это не переключатель «сделать быстрее»: накладной расход исполнения однопоточных программ в сборке --disable-gil измеряется примерно в 5–6% по сравнению с обычной сборкой. То есть за параллелизм платят однопоточной производительностью.

Backend-разработчик Python
Учебный маршрут backend-разработчика на Python: язык и среда выполнения CPython, конкурентность, веб-фреймворки и API, данные и ORM, безопасность, продакшн-инженерия и архитектура.

Backend Developer Python
Глубокое понимание Python и его среды выполнения для backend-разработки. Курс разбирает не синтаксис, а семантику языка и поведение CPython: объектную модель и работу со ссылками, модель данных и протоколы, конкурентность на asyncio и следствия глобальной блокировки интерпретатора, прикладной веб-слой (FastAPI, Django, Flask), работу с данными через ORM и продакшн-инженерию. Цель — научиться видеть стоимость абстракций и поведение кода под нагрузкой, а не просто заставлять его работать.
Готовьтесь не вслепую
Возьмите маршрут по своей роли и отрабатывайте ответы на вопросы с AI-разбором.