Interprete Python come classe C ++
-
18-09-2019 - |
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?
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.