Содержание страницы
concurrent.interpreters – Несколько интерпретаторов в одном процессе¶concurrent.interpreters – Multiple interpreters in the same process
Добавлено в версии 3.14.
Исходный код: Lib/concurrent/interpreters
Модуль concurrent.interpreters строит интерфейсы более высокого уровня поверх низкоуровневого модуля _interpreters.
Модуль в первую очередь предназначен для предоставления базового API для управления интерпретаторами (также называемыми «субинтерпретаторами») и выполнения в них кода. Выполнение в основном включает переключение на интерпретатор (в текущем потоке) и вызов функции в этом контексте выполнения.
Что касается параллелизма, сами интерпретаторы (и этот модуль) не предоставляют ничего, кроме изоляции, которая сама по себе не полезна.
Реальная параллельность доступна отдельно через threads. См. ниже
См. также
InterpreterPoolExecutorОбъединяет потоки с интерпретаторами в знакомом интерфейсе.
- Изоляция модулей расширений
Как обновить модуль расширения для поддержки нескольких интерпретаторов.
Доступность: не WASI.
Этот модуль не работает или недоступен на WebAssembly. Подробнее см. платформы WebAssembly.
Ключевые детали¶Key details
Прежде чем углубляться, стоит помнить о нескольких деталях, касающихся использования нескольких интерпретаторов:
изолированы, по умолчанию
нет неявных потоков
не все пакеты PyPI пока поддерживают использование в нескольких интерпретаторах
Введение¶Introduction
«Интерпретатор» – это, по сути, контекст выполнения среды выполнения Python. Он содержит всё состояние, необходимое среде выполнения для выполнения программы. Сюда входят такие вещи, как состояние импорта и встроенные функции. (Каждый поток, даже если есть только главный поток, имеет некоторое дополнительное состояние среды выполнения, помимо текущего интерпретатора, связанное с текущим исключением и циклом вычисления байт-кода.)
Концепция и функциональность интерпретатора были частью Python начиная с версии 2.2, но эта возможность была доступна только через C-API и не была широко известна, а изоляция была относительно неполной до версии 3.12.
Несколько интерпретаторов и изоляция¶Multiple Interpreters and Isolation
Реализация Python может поддерживать использование нескольких интерпретаторов в одном процессе. CPython поддерживает это. Каждый интерпретатор эффективно изолирован от других (за небольшим числом тщательно контролируемых исключений, глобальных для процесса).
Эта изоляция в первую очередь полезна как строгое разделение между различными логическими компонентами программы, где требуется тщательный контроль над тем, как эти компоненты взаимодействуют.
Примечание
Интерпретаторы в одном процессе технически никогда не могут быть строго изолированы друг от друга, поскольку в пределах одного процесса существует мало ограничений на доступ к памяти. Среда выполнения Python прилагает все усилия для изоляции, но модули расширения могут легко нарушить её. Поэтому не используйте несколько интерпретаторов в ситуациях, критичных с точки зрения безопасности, где они не должны иметь доступа к данным друг друга.
Выполнение в интерпретаторе¶Running in an Interpreter
Выполнение в другом интерпретаторе включает переключение на него в текущем потоке и последующий вызов некоторой функции.
Среда выполнения будет выполнять функцию, используя состояние текущего интерпретатора.
Модуль concurrent.interpreters предоставляет базовый API для создания и управления интерпретаторами, а также для операции переключения и вызова.
Никакие другие потоки не запускаются автоматически для этой операции.
Однако для этого существует вспомогательная функция.
Существует ещё одна специальная вспомогательная функция для вызова встроенной функции exec() в интерпретаторе.
Когда exec() (или eval()) вызываются в интерпретаторе, они выполняются с использованием модуля __main__ интерпретатора в качестве пространства имён «globals».
То же самое верно для функций, не связанных ни с одним модулем.
Это аналогично тому, как сценарии, запускаемые из командной строки, выполняются в модуле __main__.
Конкурентность и параллелизм¶Concurrency and Parallelism
Как отмечалось ранее, интерпретаторы сами по себе не обеспечивают никакой конкурентности. Они строго представляют изолированный контекст выполнения, который среда выполнения будет использовать в текущем потоке. Эта изоляция делает их похожими на процессы, но они по-прежнему обладают эффективностью внутри процесса, как потоки.
Тем не менее, интерпретаторы естественным образом поддерживают определённые виды конкурентности. У этой изоляции есть мощный побочный эффект. Она позволяет использовать другой подход к конкурентности, отличный от асинхронного программирования или потоков. Это модель конкурентности, похожая на CSP или модель акторов, модель, о которой относительно легко рассуждать.
Эту модель конкурентности можно использовать в одном потоке, переключаясь между интерпретаторами в стиле Stackless. Однако эта модель более полезна, когда интерпретаторы комбинируются с несколькими потоками. В основном это включает запуск нового потока, в котором переключаются на другой интерпретатор и выполняют там нужный код.
Каждый реальный поток в Python, даже если вы работаете только в главном потоке, имеет свой собственный текущий контекст выполнения. Несколько потоков могут использовать один и тот же интерпретатор или разные.
На высоком уровне можно рассматривать комбинацию потоков и интерпретаторов как потоки с возможностью совместного использования по желанию.
В качестве важного дополнительного преимущества интерпретаторы достаточно изолированы, чтобы не разделять GIL, а это означает, что сочетание потоков с несколькими интерпретаторами обеспечивает полноценный многоядерный параллелизм. (Так обстоит дело начиная с Python 3.12.)
Взаимодействие между интерпретаторами¶Communication Between Interpreters
На практике несколько интерпретаторов полезны только в том случае, если есть способ взаимодействия между ними. Обычно это подразумевает ту или иную форму передачи сообщений, но может означать и тщательно контролируемое совместное использование данных.
С учетом этого модуль concurrent.interpreters предоставляет реализацию queue.Queue, доступную через create_queue().
Ссылка¶Reference
Этот модуль определяет следующие функции:
- concurrent.interpreters.list_all()¶
Возвращает
listобъектовInterpreter, по одному для каждого существующего интерпретатора.
- concurrent.interpreters.get_current()¶
Возвращает объект
Interpreterдля текущего выполняющегося интерпретатора.
- concurrent.interpreters.get_main()¶
Возвращает объект
Interpreterдля главного интерпретатора. Это интерпретатор, созданный средой выполнения для запуска REPL или скрипта, указанного в командной строке. Обычно он единственный.
- concurrent.interpreters.create()¶
Инициализирует новый (бездействующий) интерпретатор Python и возвращает для него объект
Interpreter.
- concurrent.interpreters.create_queue()¶
Инициализирует новую очередь между интерпретаторами и возвращает для нее объект
Queue.
Объекты Interpreter¶Interpreter objects
- class concurrent.interpreters.Interpreter(id)¶
Один интерпретатор в текущем процессе.
Обычно
Interpreterне следует вызывать напрямую. Вместо этого используйтеcreate()или одну из других функций модуля.- id¶
(только для чтения)
Идентификатор соответствующего интерпретатора.
- whence¶
(только для чтения)
Строка, описывающая происхождение интерпретатора.
- is_running()¶
Возвращает
True, если интерпретатор в данный момент выполняет код в своём модуле__main__, иFalseв противном случае.
- close()¶
Финализировать и уничтожить интерпретатор.
- prepare_main(ns=None, **kwargs)¶
Привязывает объекты в модуле
__main__интерпретатора.Некоторые объекты действительно являются общими, а некоторые копируются эффективно, но большинство копируется через
pickle. См. «Совместное использование» объектов.
- exec(code, /, dedent=True)¶
Выполнить данный исходный код в интерпретаторе (в текущем потоке).
- call(callable, /, *args, **kwargs)¶
Возвращает результат вызова данной функции в интерпретаторе (в текущем потоке).
- call_in_thread(callable, /, *args, **kwargs)¶
Выполнить данную функцию в интерпретаторе (в новом потоке).
Исключения¶Exceptions
- exception concurrent.interpreters.InterpreterError¶
Это исключение, подкласс
Exception, вызывается при возникновении ошибки, связанной с интерпретатором.
- exception concurrent.interpreters.InterpreterNotFoundError¶
Это исключение, подкласс
InterpreterError, вызывается, когда целевой интерпретатор больше не существует.
- exception concurrent.interpreters.ExecutionFailed¶
Это исключение, подкласс
InterpreterError, вызывается, когда выполняемый код породил необработанное исключение.- excinfo¶
Базовый снимок исключения, возникшего в другом интерпретаторе.
Это исключение, подкласс
TypeError, вызывается, когда объект невозможно отправить другому интерпретатору.
Взаимодействие между интерпретаторами¶Communicating Between Interpreters
- class concurrent.interpreters.Queue(id)¶
Обёртка вокруг низкоуровневой очереди, работающей между интерпретаторами, которая реализует интерфейс
queue.Queue. Базовая очередь может быть создана только черезcreate_queue().Некоторые объекты действительно являются общими, а некоторые копируются эффективно, но большинство копируется через
pickle. См. «Совместное использование» объектов.- id¶
(только для чтения)
Идентификатор очереди.
- exception concurrent.interpreters.QueueEmptyError¶
Это исключение, подкласс
queue.Empty, вызывается изQueue.get()иQueue.get_nowait(), когда очередь пуста.
- exception concurrent.interpreters.QueueFullError¶
Это исключение, подкласс
queue.Full, возбуждается изQueue.put()иQueue.put_nowait(), когда очередь полна.
Базовое использование¶Basic usage
Создание интерпретатора и выполнение в нём кода:
from concurrent import interpreters
interp = interpreters.create()
# Выполнить в текущем потоке ОС.
interp.exec('print("spam!")')
interp.exec("""if True:
print('spam!')
""")
from textwrap import dedent
interp.exec(dedent("""
print('spam!')
"""))
def run(arg):
return arg
res = interp.call(run, 'spam!')
print(res)
def run():
print('spam!')
interp.call(run)
# Выполнить в новом потоке ОС.
t = interp.call_in_thread(run)
t.join()