Обзор релиза Python 3.13: Отключение GIL, JIT-компиляция и новые возможности

Разбор обновления Python 3.13: Отключение GIL, JIT-компиляция и другие новые фичи

Введение

До нового года еще два с лишним месяца, а Дед Мороз уже принес нам подарки! Буквально несколько дней назад состоялся долгожданный релиз Python 3.13, который радует разработчиков множеством новых функций и улучшений. Это обновление не только отключает GIL, позволяя потокам работать без ограничений и в режиме реальной параллельности, но и вводит JIT-компиляцию, что значительно повышает производительность кода. Давайте подробнее рассмотрим, что нового принесла эта версия и как она изменит нашу работу с Python.

Обновленный интерактивный интерпретатор Python 3.13

Как написано из официальной документации, в данном обновлении нам завозят новый интерактивный интерпретатор, основанный на коде проекта PyPy. Новая интерактивная оболочка включает следующие фичи:

  • Многострочное редактирование с сохранением истории. Теперь появилась возможность вставки многострочного кода без ошибок, ниже приведен пример вставки одного и того же блока кода в Python 3.12 и в Python 3.13.

    python interactive mode example
  • Новый интерактивный интерпретатор автоматически подставляет табуляции при объявлении функций и классов.

  • Добавили горячие клавиши: f1 для просмотра справки, f2 для просмотра истории, f3 для активации «Режим вставки», который упрощает вставку

  • Прямая поддержка специфичных для REPL команд, таких как help, exit, и quit, без необходимости вызывать их как функции.

  • Подсказки и трассировки по умолчанию имеют включенную подсветку кода.

Новый обновленный интерактивный интерпретатор стал значительно удобнее, чем его предшественник, и станет незаменимым инструментом в моем арсенале.

Улучшили сообщения об ошибках

В Python 3.13 улучшили сообщения об ошибках, их сделали более информативными и полезными для разработчиков. Теперь:

  • Теперь интерпретатор по умолчанию использует цвет при отображении трассировок, что упрощает их восприятие.

  • Если имя скрипта совпадает с именем стандартного или стороннего модуля, выводится рекомендация переименовать скрипт для избежания конфликтов. Например, если создать модуль под названием random.py и попытаться в этом модуле вызвать функцию из стандартной библиотеки random, то получим следующее сообщение об ошибке: AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it has the same name as the standard library module named 'random' and the import system gives it precedence)

  • При передаче неверного аргумента ключевого слова функция теперь предлагает корректное название. Для примера передадим методу split несуществующий ключевой именованный аргумент max_split и получим улучшенное сообщение об ошибке: TypeError: split() got an unexpected keyword argument 'max_split'. Did you mean 'maxsplit'?

Эти изменения делают отладку кода проще и позволяют быстрее находить и исправлять ошибки.

Оптимизация производительности Python 3.13 с помощью экспериментального JIT-компилятора

В Python 3.13 внедрен экспериментальный компилятор just-in-time (JIT), который значительно повышает производительность приложений благодаря новой архитектуре обработки байт-кода. При включении JIT компилятор трансформирует «горячий» байт-код первого уровня в более эффективное промежуточное представление (IR) второго уровня, оптимизированное для перевода в машинный код. Это позволяет применять несколько этапов оптимизации перед фактическим выполнением кода, существенно сокращая время работы программ. На данный момент это обновление является экспериментальным и не включено в стандартный дистрибутив. Чтобы воспользоваться JIT, необходимо собрать Python 3.13 из исходников с флагом --enable-experimental-jit. Более подробную информацию можно найти в официальной документации.

Python 3.13 и мобильные платформы: теперь поддерживаются iOS и Android

С выходом Python 3.13 теперь поддерживаются мобильные платформы iOS и Android! Для устройств Apple, таких, как iPhone и iPad, выпущенных после 2013 года, и симуляторов на Apple Silicon, добавлена поддержка с помощью специальной платформы. Это значит, что разработчики могут создавать приложения для этих устройств более эффективно. Для Android также появилась поддержка современных архитектур, таких как aarch64 и x86_64, что позволит запускать Python-программы на большем количестве устройств. Хотя старые 32-разрядные системы не входят в основной список поддерживаемых, они все равно получат некоторую функциональность. Это открывает новые возможности для разработки приложений на Python на мобильных платформах. Более подробно об этом можно почитать в официальной документации.

Отключение GIL в Python 3.13: Как ускорить многопоточные задачи и повысить производительность

Одним из самых значимых нововведений в Python 3.13 стало экспериментальное отключение глобальной блокировки интерпретатора (GIL). Эта функция открывает возможность для полного параллелизма в многопоточных задачах, делая Python более производительным на многоядерных системах. Однако, для её использования требуется отдельная версия интерпретатора, обычно она называется python3.13t или python3.13t.exe. На Windows или Macos вы сможете установить ее через стандартный установщик Python (нужный параметр выделен на скриншоте ниже), изменив параметр установки, или собрать из исходного кода с флагом --disable-gil.

python3.13 installer

Как управлять GIL в Python 3.13

GIL можно контролировать с помощью переменной окружения PYTHON_GIL или аргумента командной строки -X gil. Например, для отключения GIL при запуске скрипта используйте такую команду: python3.13t -X gil=0 test_gil.py

Важное уточнение, данный аргумент не работает в стандартной сборке Python 3.13, интерпретатор выведет предупреждение. Как и писал выше, данный аргумент поддерживается бинарниками python c только припиской t в конце, либо собранным интерпретатором со специальным флагом.

Производительность многопоточных сценариев в Python 3.13 на примере вычисления факториала

Ниже приведен пример простого скрипта, который вычисляет факториалы чисел с использованием трех подходов: однопоточного, многопоточного и мультипроцессорного


import math
import time
import threading
import multiprocessing

def compute_factorial(n):
return math.factorial(n)

# Однопоточное исполнение
def single_threaded_compute(n):
for num in n:
    compute_factorial(num)
print("Факториал вычислен в один поток.")

# Многопоточное исполнение
def multi_threaded_compute(n):
threads = []
for num in n:
    thread = threading.Thread(target=compute_factorial, args=(num,))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()
print("Факториал вычислен в 5 потоков.")

# Мультипроцессорное исполнение
def multi_processing_compute(n):
processes = []
for num in n:
    process = multiprocessing.Process(target=compute_factorial, args=(num,))
    processes.append(process)
    process.start()

for process in processes:
    process.join()
print("Факториал вычислен в мультипроцессорном режиме.")

if __name__ == "__main__":
numlist = [100000, 200000, 300000, 400000, 500000]
start = time.time()
single_threaded_compute(numlist)
print(f"Время исполнения в один поток: {time.time() - start:.2f} секунд")

start = time.time()
multi_threaded_compute(numlist)
print(f"Многопоточное время исполнения: {time.time() - start:.2f} секунд")

start = time.time()
multi_processing_compute(numlist)
print(f"Мультипроцессорное время исполнения: {time.time() - start:.2f} секунд")

Запустив этот скрипт с отключенным GIL, вы увидите, что многопоточные задачи выполняются быстрее за счет параллельного использования нескольких ядер процессора. В то же время, однопоточные и мультипроцессорные задачи могут показать небольшое снижение производительности. Например, при отключении GIL время выполнения однопоточного кода может увеличиться на ~10%, что связано с изменениями в работе сборщика мусора и управлении памятью.

Как проверить статус GIL вашего интерпретатора

Для проверки, активирован ли свободный поток в вашем интерпретаторе, можно воспользоваться следующим кодом:

import sysconfig print(sysconfig.get_config_var("Py_GIL_DISABLED"))
Если GIL отключён, команда вернёт 1. Если включён — 0

Когда отключение GIL полезно

Отключение GIL может быть целесообразно в проектах, которые используют множество потоков, в остальных случаях наблюдается ухудшение производительности из-за дополнительных накладных расходов на управление памятью и сборку мусора. Для разработчиков, создающих приложения с активным использованием потоков, отключение GIL может стать ключевым фактором в повышении производительности, делая Python более конкурентоспособным в многопоточных задачах.

Новые изменения в работе функции locals() в Python 3.13

В Python 3.13 изменена семантика встроенной функции locals(), которая теперь по-новому работает с оптимизированными областями видимости, такими как функции, генераторы и сопрограммы. Теперь она возвращает независимые снимки (снапшоты) локальных переменных на момент вызова, а также не локальных переменных, использованных в замыканиях. Это улучшение позволяет избежать изменений переменных после вызова функции и делает ее поведение более предсказуемым при работе в таких контекстах, как генераторы и асинхронные функции.

Новая библиотека памяти mimalloc теперь по умолчанию в Python 3.13

В стандартный дистрибутив интерпретатора Python 3.13 включили измененную версию библиотеки распределения памяти mimalloc, разработанная Microsoft. Эта библиотека отличается высокой производительностью и задействована в сборках Python без глобальной блокировки интерпретатора (GIL).

Оптимизация встроенной документации в Python 3.13: Экономия памяти и уменьшение байткода

Теперь в Python 3.13 компилятор теперь автоматически удаляет отступы из строк документации (docstring), что позволяет значительно сократить использование памяти. Это нововведение уменьшает размер байткод кэшей (.pyc файлов) примерно на 5%, что особенно полезно при работе с крупными проектами, где объем сгенерированного байт кода может быть значительным. Благодаря этой оптимизации, питонячие программы становятся более компактными и эффективными в плане хранения.

Нововведения в модуле dbm: поддержка SQLite

Модуль dbm теперь включает бэкенд dbm.sqlite3, который использует SQLite для хранения данных. Это решение становится бэкендом по умолчанию при создании новых файлов, что упрощает работу с файлами баз данных и обеспечивает лучшую производительность и совместимость с современными системами хранения.

Улучшение типизации в Python 3.13: поддержка значений по умолчанию

Добавлена поддержка указания значений по умолчанию в параметрах типов, таких как TypeVar, ParamSpec и TypeVarTuple. Это позволяет создавать типы с дефолтными значениями, улучшая гибкость аннотаций. Например, теперь можно определить переменную типа следующим образом:

T = TypeVar("T", default=int)

Это упрощает работу с типами и делает код более понятным.

Новая аннотация typing.TypeIs в Python 3.13: улучшение проверки типов

Добавлена аннотация typing.TypeIs, которая предназначена для уточнения типов. Она предлагает более интуитивно понятный подход по сравнению с typing.TypeGuard. Это нововведение облегчает разработчикам задачу по проверке типов, делая код менее громоздким и более читабельным.

Пометка элементов только для чтения typing.ReadOnly в Python 3.13

Была добавлена аннотация typing.ReadOnly, с помощью которой можно отмечать элементы TypedDicts, доступные только для чтения. Это позволяет более чётко управлять данными, исключая возможность изменения ключевых элементов и защищая целостность данных внутри структур TypedDict.

Пометка устаревших элементов через warnings.deprecated() в Python 3.13

Теперь в систему типов добавлена функция warnings.deprecated(), которая используется для обозначения устаревших элементов. Это обновление помогает лучше отслеживать, какие компоненты кода следует избегать, тем самым улучшая процесс поддержки и обновления приложений.

Пометка устаревших элементов через warnings.deprecated() в Python 3.13

Из стандартной библиотеки Python были удалены следующие модули:

  • aifc
  • audioop
  • chunk
  • cgi
  • cgitb
  • crypt
  • imghdr
  • mailcap
  • msilib
  • nis
  • nntplib
  • ossaudiodev
  • pipes
  • sndhdr
  • spwd
  • sunau
  • telnetlib
  • uu
  • xdrlib
  • lib2to3

Новая функция copy.replace() в модуле copy

Модуль copy теперь включает новую функцию copy.replace(). Она позволяет заменить элементы копируемых объектов, улучшая контроль над процессом копирования. Это нововведение делает модуль более гибким и функциональным для сложных операций с объектами.

Новые функции работы с таймерами в модуле os

В модуль os добавлены функции, которые позволяют работать с таймерами через файловые дескрипторы. Эти функции делают работу с таймерами более удобной, особенно в сценариях, связанных с низкоуровневыми операциями и системным программированием.

Интерфейс командной строки для модуля random

Теперь модуль random поддерживает интерфейс командной строки, что позволяет генерировать случайные числа напрямую через консоль. Это нововведение может быть полезно для быстрого получения случайных значений без необходимости написания отдельного скрипта.

Заключение

Несомненно Python 3.13 является самым глобальным обновлением для языка программирования за последние годы. Отключение GIL и внедрение JIT-компиляции открывают двери для более эффективного использования многопоточности и оптимизации производительности приложений. Улучшенные сообщения об ошибках и обновленный интерактивный интерпретатор делают процесс разработки более удобным и интуитивным. Поддержка мобильных платформ расширяет горизонты применения Python, позволяя создавать приложения на iOS и Android. Важно отметить, что, хотя новые функции еще находятся на экспериментальной стадии, они уже показывают огромный потенциал для трансформации нашего подхода к разработке.

Дата создания публикации:

Теги: python

Прочтений: 3307