free-threading-python.md
1> **Источник:** https://python-all.ru/3.16/howto/free-threading-python.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Поддержка свободной многопоточности в Python89Начиная с версии 3.13, CPython поддерживает сборку Python, называемую [свободная многопоточность](https://python-all.ru/3.16/glossary.html#term-free-threading), в которой [глобальная блокировка интерпретатора](https://python-all.ru/3.16/glossary.html#term-global-interpreter-lock) (GIL) отключена. Выполнение со свободной многопоточностью позволяет полностью задействовать доступную вычислительную мощность, запуская потоки параллельно на доступных ядрах CPU. Хотя не всё программное обеспечение выигрывает от этого автоматически, программы, спроектированные с учётом многопоточности, будут работать быстрее на многоядерном оборудовании.1011Некоторые сторонние пакеты, особенно те, что содержат [модуль расширения](https://python-all.ru/3.16/glossary.html#term-extension-module), могут быть не готовы к использованию в сборке со свободной многопоточностью и будут повторно включать [GIL](https://python-all.ru/3.16/glossary.html#term-GIL).1213В этом документе описываются последствия свободной многопоточности для Python-кода. Информацию о том, как писать расширения на C, поддерживающие сборку со свободной многопоточностью, см. в [C API Extension Support for Free Threading](https://python-all.ru/3.16/howto/free-threading-extensions.html#freethreading-extensions-howto).1415> **См. также**16>17> [**PEP 703**](https://python-all.ru/3.16/howto/free-threading-python.html) – «Сделать глобальную блокировку интерпретатора опциональной в CPython» для общего описания Python со свободной многопоточностью.1819## Установка2021Начиная с Python 3.13, официальные установщики для macOS и Windows опционально поддерживают установку двоичных файлов Python со свободной многопоточностью. Установщики доступны по адресу [https://www.python.org/downloads/](https://python-all.ru/3.16/howto/free-threading-python.html).2223Информацию о других платформах см. в [Installing a Free-Threaded Python](https://python-all.ru/3.16/howto/free-threading-python.html), руководстве по установке, поддерживаемом сообществом, для установки Python со свободной многопоточностью.2425При сборке CPython из исходного кода для создания свободно-поточной сборки интерпретатора Python следует использовать опцию конфигурации [`--disable-gil`](https://python-all.ru/3.16/using/configure.html#cmdoption-disable-gil).2627## Определение сборки со свободной потоковой обработкой2829Чтобы проверить, поддерживает ли текущий интерпретатор свободную потоковую обработку, [`python -VV`](https://python-all.ru/3.16/using/cmdline.html#cmdoption-V) и [`sys.version`](https://python-all.ru/3.16/library/sys.html#sys.version) содержат строку "free-threading build". Новая функция [`sys._is_gil_enabled()`](https://python-all.ru/3.16/library/sys.html#sys._is_gil_enabled) позволяет определить, отключена ли GIL в работающем процессе.3031Переменная конфигурации `sysconfig.get_config_var("Py_GIL_DISABLED")` позволяет определить, поддерживает ли сборка свободную потоковую обработку. Если переменная имеет значение `1`, то сборка поддерживает свободную потоковую обработку. Это рекомендуемый механизм для принятия решений, связанных с конфигурацией сборки.3233## Глобальная блокировка интерпретатора в сборке со свободной потоковой обработкой3435Сборки CPython со свободной потоковой обработкой поддерживают опциональную работу с включённой GIL во время выполнения с помощью переменной окружения [`PYTHON_GIL`](https://python-all.ru/3.16/using/cmdline.html#envvar-PYTHON_GIL) или опции командной строки [`-X gil`](https://python-all.ru/3.16/using/cmdline.html#cmdoption-X).3637GIL также может автоматически включаться при импорте модуля расширения C-API, который явно не помечен как поддерживающий свободную потоковую обработку. В этом случае будет выведено предупреждение.3839В дополнение к документации отдельных пакетов, следующие сайты отслеживают статус поддержки свободной потоковой обработки популярными пакетами:4041- [https://py-free-threading.github.io/tracking/](https://python-all.ru/3.16/howto/free-threading-python.html)42- [https://hugovk.github.io/free-threaded-wheels/](https://python-all.ru/3.16/howto/free-threading-python.html)4344## Потокобезопасность4546Сборка CPython со свободной потоковой обработкой стремится обеспечить на уровне Python поведение, аналогичное потокобезопасности сборки со включённой GIL по умолчанию. Встроенные типы, такие как [`dict`](https://python-all.ru/3.16/library/stdtypes.html#dict), [`list`](https://python-all.ru/3.16/library/stdtypes.html#list) и [`set`](https://python-all.ru/3.16/library/stdtypes.html#set), используют внутренние блокировки для защиты от одновременных изменений подобно GIL. Однако исторически Python не гарантировал конкретного поведения при одновременных изменениях этих встроенных типов, поэтому это следует рассматривать как описание текущей реализации, а не как гарантию текущего или будущего поведения.4748> **Примечание**49>50> По возможности рекомендуется использовать [`threading.Lock`](https://python-all.ru/3.16/library/threading.html#threading.Lock) или другие примитивы синхронизации вместо того, чтобы полагаться на внутренние блокировки встроенных типов.5152## Известные ограничения5354В этом разделе описаны известные ограничения сборки CPython со свободной потоковой обработкой.5556### Иммортализация5758В сборке со свободной потоковой обработкой некоторые объекты [иммортальны](https://python-all.ru/3.16/glossary.html#term-immortal). Иммортальные объекты не освобождаются, и их счётчики ссылок никогда не изменяются. Это делается для предотвращения конкуренции за счётчики ссылок, которая мешала бы эффективному масштабированию в многопоточных сценариях.5960По состоянию на версию 3.14 иммортализация ограничена:6162- Константами кода: числовыми литералами, строковыми литералами и литералами кортежей, состоящими из других констант.63- Строками, интернированными с помощью [`sys.intern()`](https://python-all.ru/3.16/library/sys.html#sys.intern).6465### Объекты фреймов6667Обращаться к [`frame.f_locals`](https://python-all.ru/3.16/reference/datamodel.html#frame.f_locals) из объекта [frame](https://python-all.ru/3.16/reference/datamodel.html#frame-objects) небезопасно, если этот фрейм в данный момент выполняется в другом потоке; это может привести к аварийному завершению интерпретатора.6869### Итераторы7071Обращаться к одному и тому же объекту итератора одновременно из нескольких потоков, как правило, небезопасно – потоки могут видеть дублирующиеся или пропущенные элементы.7273### Производительность в однопоточном режиме7475Сборка со свободной потоковой обработкой имеет дополнительные накладные расходы при выполнении кода Python по сравнению со сборкой со включённой GIL по умолчанию. Величина накладных расходов зависит от нагрузки и оборудования. В тестовом наборе pyperformance средние накладные расходы составляют от примерно 1% на macOS aarch64 до 8% на системах x86-64 Linux.7677## Изменения в поведении7879В этом разделе описаны изменения в поведении CPython в сборке со свободной потоковой обработкой.8081### Контекстные переменные8283В сборке со свободной потоковой обработкой флаг [`thread_inherit_context`](https://python-all.ru/3.16/library/sys.html#sys.flags.thread_inherit_context) по умолчанию имеет значение true, из-за чего потоки, созданные с помощью [`threading.Thread`](https://python-all.ru/3.16/library/threading.html#threading.Thread), запускаются с копией [`Context()`](https://python-all.ru/3.16/library/contextvars.html#contextvars.Context) вызывающей стороны [`start()`](https://python-all.ru/3.16/library/threading.html#threading.Thread.start). В сборке со включённой GIL по умолчанию флаг по умолчанию равен false, поэтому потоки запускаются с пустым `Context()`.8485### Фильтры предупреждений8687В сборке со свободной потоковой обработкой флаг [`context_aware_warnings`](https://python-all.ru/3.16/library/sys.html#sys.flags.context_aware_warnings) по умолчанию имеет значение true. В сборке со включённой GIL по умолчанию флаг по умолчанию равен false. Если флаг имеет значение true, то контекстный менеджер [`warnings.catch_warnings`](https://python-all.ru/3.16/library/warnings.html#warnings.catch_warnings) использует контекстную переменную для фильтров предупреждений. Если флаг равен false, то `catch_warnings` изменяет глобальный список фильтров, что не является потокобезопасным. Подробнее см. в модуле [`warnings`](https://python-all.ru/3.16/library/warnings.html#module-warnings).8889### Увеличенное потребление памяти9091Сборка со свободными потоками обычно использует больше памяти по сравнению со стандартной сборкой. На это есть несколько причин, в основном связанных с проектными решениями.9293#### Все интернированные строки являются бессмертными9495В современных версиях Python (начиная с версии 2.3) интернирование строки (например, с помощью [`sys.intern()`](https://python-all.ru/3.16/library/sys.html#sys.intern)) не делает её бессмертной. Вместо этого, если последняя ссылка на эту строку исчезает, она удаляется из таблицы интернированных строк. В сборке со свободными потоками это не так, и любая интернированная строка становится бессмертной, существуя до завершения интерпретатора.9697#### Объекты, не поддерживающие сборку мусора, имеют больший заголовок объекта9899Сборка со свободными потоками использует другую структуру [`PyObject`](https://python-all.ru/3.16/c-api/structures.html#c.PyObject). Вместо того чтобы выделять информацию, связанную с GC, перед структурой `PyObject` как в стандартной сборке, информация о GC является частью обычного заголовка объекта. Например, на платформе AMD64 `None` использует 32 байта на сборке со свободными потоками против 16 байт в стандартной сборке. GC-объекты (такие как словари и списки) имеют одинаковый размер в обеих сборках, поскольку сборка со свободными потоками не использует дополнительное место для информации о GC.100101#### QSBR может задерживать освобождение памяти102103Чтобы безопасно реализовать структуры данных без блокировок, используется схема безопасной памяти (SMR), известная как освобождение на основе состояния покоя (QSBR). Это означает, что память, лежащая в основе структур данных, допускающих доступ без блокировок, будет использовать QSBR, который откладывает операцию освобождения, а не немедленно освобождает память. Два примера таких структур данных – объект списка и объект ключей словаря. См. `InternalDocs/qsbr.md` в дереве исходных кодов CPython для получения дополнительных сведений о том, как реализован QSBR. Запуск [`gc.collect()`](https://python-all.ru/3.16/library/gc.html#gc.collect) должен привести к тому, что вся память, удерживаемая QSBR, будет фактически освобождена. Обратите внимание, что даже когда QSBR освобождает память, нижележащий распределитель памяти может не вернуть эту память обратно операционной системе немедленно, поэтому резидентный размер (RSS) процесса может не уменьшиться.104105#### Распределитель mimalloc против pymalloc106107Стандартная сборка обычно использует распределитель памяти «pymalloc» для мелких выделений (512 байт или меньше). Сборка со свободными потоками не использует pymalloc и выделяет все объекты Python с помощью распределителя «mimalloc». Распределитель pymalloc обладает следующими свойствами, которые помогают поддерживать низкое потребление памяти: малые накладные расходы на каждый выделенный блок, эффективное предотвращение фрагментации памяти и быстрый возврат свободной памяти операционной системе. Распределитель mimalloc также хорошо справляется с этими аспектами, но может иметь некоторые дополнительные накладные расходы.108109В сборке со свободными потоками mimalloc управляет памятью в нескольких отдельных кучах (в настоящее время четыре). Например, все объекты, поддерживающие сборку мусора, выделяются из собственной кучи. Использование отдельных куч означает, что свободная память в одной куче не может быть использована для выделения, использующего другую кучу. Кроме того, некоторые кучи настроены на использование QSBR (освобождение на основе состояния покоя) при освобождении памяти, резервирующей кучу (известную как «страницы» в терминологии mimalloc). Использование QSBR создаёт задержку между тем, как все блоки памяти для страницы освобождены и страница памяти освобождается – либо для новых выделений, либо обратно операционной системе.110111Распределитель mimalloc также откладывает возврат освобождённой памяти обратно ОС. Эту задержку можно уменьшить, установив переменную окружения `MIMALLOC_PURGE_DELAY` в значение `0`. Обратите внимание, что это, вероятно, снизит производительность распределителя.112113#### Подсчёт ссылок в свободнопоточной сборке может приводить к более долгому времени жизни объектов114115В стандартной сборке, когда счётчик ссылок объекта достигает нуля, он обычно освобождается. Сборка со свободными потоками использует «смещённый подсчёт ссылок» (biased reference counting) с быстрым путём для объектов, «принадлежащих» текущему потоку, и медленным путём для других объектов. См. [**PEP 703**](https://python-all.ru/3.16/howto/free-threading-python.html) для получения дополнительных сведений. Когда счётчик ссылок объекта оказывается в состоянии «в очереди», освобождение может быть отложено. Состояние очереди сбрасывается в секции «eval breaker» интерпретатора байткода.116117Сборка со свободными потоками также поддерживает другой режим подсчёта ссылок, известный как «отложенный подсчёт ссылок». Этот режим включается установкой флага для каждого объекта отдельно. Отложенный подсчёт ссылок включён для следующих типов:118119- объекты модулей120- функции верхнего уровня модулей121- методы классов, определённые в пространстве имён класса122- объекты дескрипторов123- потоково-локальные объекты, созданные с помощью [`threading.local`](https://python-all.ru/3.16/library/threading.html#threading.local)124125Когда отложенный подсчёт ссылок включён, ссылки из стеков вызовов функций Python не добавляются к счётчику ссылок. Эта схема снижает накладные расходы подсчёта ссылок, особенно для объектов, используемых из нескольких потоков. Поскольку ссылки из стека не учитываются, объекты с отложенным подсчётом ссылок не освобождаются сразу, когда их внутренний счётчик ссылок достигает нуля. Вместо этого они проверяются при следующем запуске GC, и если ссылки на них из стека не найдены, они освобождаются. Это означает, что такие объекты освобождаются GC, а не при обнулении их счётчика ссылок, как это обычно происходит.126127#### Попоточный подсчёт ссылок может задерживать освобождение объектов128129Чтобы избежать конкуренции за поля счётчика ссылок часто разделяемых объектов, сборка со свободными потоками также использует «попоточный подсчёт ссылок» для нескольких выбранных типов объектов. Вместо обновления одного общего счётчика ссылок каждый поток ведёт свой собственный локальный массив счётчиков ссылок, индексируемый уникальным идентификатором, присвоенным объекту. Истинный счётчик ссылок вычисляется только суммированием попоточных счётчиков, когда локальный счётчик объекта обнуляется. Попоточный подсчёт ссылок в настоящее время используется для:130131- объекты типов кучи (классы, определённые в Python)132- объекты кода133- словарь `__dict__` объектов модулей134135Поскольку попоточные счётчики должны быть объединены обратно в объект, прежде чем он может быть освобождён, объекты, использующие попоточный подсчёт ссылок, обычно освобождаются позже, чем в стандартной сборке. В частности, такой объект обычно не освобождается до тех пор, пока поток, который ссылался на него, не достигнет безопасной точки (например, в секции «eval breaker» интерпретатора байткода) или не завершится. Запуск [`gc.collect()`](https://python-all.ru/3.16/library/gc.html#gc.collect) объединит попоточные счётчики и позволит освободить эти объекты.136