Что такое субинтерпретаторы в Python и зачем они нужны

Ответ

Субинтерпретаторы (Subinterpreters) в Python — это механизм, позволяющий запускать несколько изолированных экземпляров интерпретатора Python в рамках одного процесса.

Основная цель их введения — достижение истинного параллелизма для CPU-bound задач путем обхода ограничений глобальной блокировки интерпретатора (GIL), поскольку каждый субинтерпретатор имеет свой собственный GIL.

Ключевые особенности

  • Изоляция GIL: Каждый субинтерпретатор имеет свою собственную блокировку GIL, что позволяет коду в разных субинтерпретаторах выполняться по-настоящему параллельно на многоядерных процессорах.
  • Изоляция состояния: Объекты и глобальные переменные не разделяются между субинтерпретаторами, что предотвращает гонки данных, но усложняет взаимодействие.
  • Обмен данными: Взаимодействие между ними возможно только через специальные каналы (channels), что обеспечивает безопасность.

Пример использования (экспериментальный API)

# Модуль является экспериментальным и может измениться
import _xxsubinterpreters as subinterpreters
import textwrap

# Создаем новый субинтерпретатор
interp_id = subinterpreters.create()

# Код для выполнения в новом интерпретаторе
code = textwrap.dedent("""
    import threading
    print(f"Hello from subinterpreter! Thread ID: {threading.get_ident()}")
""")

# Запускаем код в созданном субинтерпретаторе
subinterpreters.run_string(interp_id, code)

# Уничтожаем субинтерпретатор для освобождения ресурсов
subinterpreters.destroy(interp_id)

На данный момент (Python 3.12) API для работы с субинтерпретаторами все еще считается нестабильным и не предназначен для использования в production. Однако работа над ним активно ведется, и в будущем он может стать стандартным способом для параллельных вычислений в Python.

Ответ 18+ 🔞

Да ты послушай, что эти умники придумали! Субинтерпретаторы, блядь. Ну, представляешь, как будто в одной хате несколько квартир, и в каждой — свой, ёпта, отдельный пайтон живёт, со своим замком на двери (это GIL, если что). И главное — они друг другу не мешают! Один там интегралы ебёт, другой — JSON'ы парсит, и оба по-настоящему, на разных ядрах процессора, а не как обычно, по очереди, как последние лохи.

Чё за фишка, внатуре:

  • Свой GIL, как личный горшок: У каждого субинтерпретатора — своя блокировка. Нет больше этой всенародной очереди в один сортир. Хуй с горы — работай параллельно, если железо позволяет.
  • Полная изоляция, как в боксе: Объекты из одной "квартиры" в другую просто так не переедут. Гонки данных? Нет, не слышали. Но и просто так пообщаться не выйдет — придётся через спецканалы, как через трубку домофона.
  • Общаться — только по каналам: Взаимодействие есть, но контролируемое, чтоб не началась драка за общий телевизор.

Смотри, как это выглядит (но это пока что чисто экспериментал, на коленке, блядь!):

# Модуль — тот ещё подопытный кролик, всё может поменяться
import _xxsubinterpreters as subinterpreters
import textwrap

# Создаём новую изолированную хату-интерпретатор
interp_id = subinterpreters.create()

# Код, который будет там внутри вариться
code = textwrap.dedent("""
    import threading
    print(f"Hello from subinterpreter! Thread ID: {threading.get_ident()}")
""")

# Запуляем этот код в новосозданной квартире
subinterpreters.run_string(interp_id, code)

# После вечеринки — убираем за собой, уничтожаем интерпретатор
subinterpreters.destroy(interp_id)

Вот такая, блядь, картина. Пока что это как игрушка для гиков в Python 3.12 — трогать в продакшене страшно, всё может накрыться медным тазом. Но идея-то, сука, огонь! Если её доведут до ума, это ж будет настоящий прорыв, чтобы наконец-то заставить CPU-bound задачи в Питоне пахать, как проклятые, а не переминаться с ноги на ногу.