2009-09-26 8 views
8

Sto lavorando per incorporare python in C++. In qualche caso particolare, ho bisogno di due istanze separate dell'interprete nello stesso thread.Interprete Python come classe C++

Posso eseguire il wrapping dell'interprete Python in una classe C++ e ottenere servizi da due o più istanze di classe?

risposta

14

ho usato 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(); 

Ad ogni istanza interprete (in qualsiasi 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 

Nota che è necessario un myThreadState variabile per ogni interprete esempio!

infine al traguardo 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.

4

Si può, ma io raccomanderei di non ri-implementare un interprete Python quando c'è un'implementazione standard. Usa boost :: python per interfacciare con Python.

+0

boost python utilizza python c apis. è possibile avviare l'interprete due volte chiamando Py_Initialize()? –

6

Callin Py_Initialize() due volte non funziona bene, tuttavia Py_NewInterpreter può funzionare, a seconda di ciò che si sta tentando di fare. Leggi attentamente i documenti, devi tenere premuto il GIL quando lo chiami.

+0

Immagino che non otterrò una risposta diretta alla mia domanda. La tua risposta mi ha dato alcuni input sui quali posso iniziare a lavorare. Py_NewInterpreter sembra essere l'opzione corretta per iniziare ad esplorare lo scenario che ho descritto. Sulla base di questo, accetto la tua risposta. –

1

Non penso che tu sia il primo a volerlo fare, purtroppo credo che non sia possibile. Sei in grado di eseguire interpolatori Python come processi separati e utilizzare RPC?

0
  • È possibile lasciare l'interprete Python al di fuori dello spazio di memoria dell'applicazione. Basta incorporare l'interprete in una DLL.
  • È possibile impostare & salvare contesti python per simulare due diversi interpreti.
1

La risposta di mosaik non ha funzionato nella mia situazione in cui il mio modulo è un plugin per un'applicazione host che già inizializza python. Sono stato in grado di 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 ha prodotto. Inoltre, chiamare PyEval_ReleaseThread(myState) sembrava invalidare anche l'interprete.