Domanda

Sto lavorando a incorporare Python in C ++. In qualche caso particolare ho bisogno di due istanze separate del interprete stesso thread.

Posso avvolgere interprete Python in un c ++ classe e di ottenere servizi di due o più istanze della classe?

È stato utile?

Soluzione

Ho utilizzato Py_NewInterpreter per diversi interpreti in diversi thread, ma questo dovrebbe funzionare anche per diversi interpreti entro un filo:

Nel thread principale:

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

Per ogni istanza interprete (in ogni thread):

// 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

Si noti che è necessario un myThreadState variabile per ogni istanza dell'interprete!

Infine la finitura nel thread principale:

PyEval_RestoreThread(mainThreadState);
Py_Finalize();

Ci sono alcune restrizioni con l'utilizzo di diversi casi interprete (che non sembrano essere totalmente indipendenti), ma nella maggior parte dei casi questo non sembra causare problemi.

Altri suggerimenti

Callin Py_Initialize() due volte non funziona bene, tuttavia Py_NewInterpreter può lavorare, a seconda di quello che stai cercando di fare. Leggere con attenzione la documentazione, è necessario tenere premuto il GIL quando si chiama questo.

È possibile, ma vi consiglio di non re-implementare un interprete Python quando c'è un'implementazione standard. Utilizza boost :: python per interfacciarsi con Python.

Non credo che tu sei la prima persona a voler fare questo, purtroppo credo che non è possibile. Sei in grado di eseguire i o interprete Python come processi separati e utilizzare RPC?

La risposta di Mosaik non ha funzionato nella mia situazione in cui il mio modulo è un plugin per un'applicazione host che inizializza già pitone. Sono riuscito a farlo funzionare con il seguente codice.

// 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)

Quando ho chiamato PyEval_AcquireLock() il programma bloccato e la funzione non tornò. Inoltre, chiamando PyEval_ReleaseThread(myState) sembrava invalidare l'interprete anche.

  • È possibile lasciare che l'interprete Python al di fuori dal vivo del proprio spazio di memoria dell'applicazione. Basta inserire l'interprete in una DLL.
  • È possibile impostare e salvare contesti pitone per simulare due interpreti diversi.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top