Вопрос

Я работаю над внедрением Python в С++.В каком-то необычном случае мне нужны два отдельных экземпляра интерпретатора в одном потоке.

Могу ли я включить интерпретатор Python в класс C++ и получать услуги от двух или более экземпляров класса?

Это было полезно?

Решение

Я использовал Py_NewInterpreter для разных интерпретаторов в разных потоках, но это также должно работать для нескольких интерпретаторов в одном потоке:

В основной теме:

Py_Initialize();
PyEval_InitThreads();
mainThreadState = PyEval_SaveThread();

Для каждого экземпляра интерпретатора (в любом потоке):

// initialize interpreter
PyEval_AcquireLock();                // get the GIL
myThreadState = Py_NewInterpreter();
... // call python code
PyEval_ReleaseThread(myThreadState); // swap out thread state + release the GIL

... // any other code

// continue with interpreter
PyEval_AcquireThread(myThreadState); // get GIL + swap in thread state
... // call python code
PyEval_ReleaseThread(myThreadState);

... // any other code

// finish with interpreter
PyEval_AcquireThread(myThreadState);
... // call python code
Py_EndInterpreter(myThreadState);
PyEval_ReleaseLock();                // release the GIL

Обратите внимание, что вам нужна переменная myThreadState для каждого экземпляра интерпретатора!

Наконец завершение основной темы:

PyEval_RestoreThread(mainThreadState);
Py_Finalize();

Существуют некоторые ограничения на использование нескольких экземпляров интерпретатора (они не кажутся полностью независимыми), но в большинстве случаев это не вызывает проблем.

Другие советы

Вызывать Py_Initialize() дважды, однако, это не сработает Py_NewInterpreter может работать, в зависимости от того, что вы пытаетесь сделать.Внимательно прочитайте документацию, при вызове необходимо удерживать GIL.

Вы можете, но я бы рекомендовал вам не переопределять интерпретатор Python, если существует стандартная реализация.Использовать повышение::питон для взаимодействия с Python.

Я не думаю, что вы первый, кто захочет это сделать, к сожалению, я считаю, что это невозможно.Можете ли вы запускать интерпретаторы Python как отдельные процессы и использовать RPC?

Ответ mosaik не сработал в моей ситуации, когда мой модуль представляет собой плагин для хост-приложения, которое уже инициализирует Python.Мне удалось заставить его работать с помощью следующего кода.

// initialize interpreter
::PyEval_InitThreads();
::PyThreadState *mainThread = ::PyThreadState_Get();
myState = ::Py_NewInterpreter();
... // call python code
::PyThreadState_Swap(mainThread);

... // any other code

mainThread = ::PyThreadState_Swap(myState)
... // call python code
::PyThreadState_Swap(mainThread)

... // any other code

// finished with interpreter
mainThread = ::PyThreadState_Swap(myState)
::Py_EndInterpreter(myState);
::PyThreadState_Swap(mainThread)

Когда я позвонил PyEval_AcquireLock() программа заблокировалась и функция не вернулась.Далее, вызывая PyEval_ReleaseThread(myState) казалось, лишило законной силы и переводчика.

  • Вы можете позволить интерпретатору Python жить за пределами памяти вашего приложения.Просто встройте интерпретатор в DLL.
  • Вы можете настроить и сохранить контексты Python для имитации двух разных интерпретаторов.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top