2012-02-07 16 views
5

Stiamo sviluppando un'applicazione server c piccola. L'applicazione server esegue alcuni processi di elaborazione dati e risponde al client. Per mantenere la parte di elaborazione dati configurabile e flessibile abbiamo deciso di utilizzare lo scripting e in base alla disponibilità di vari moduli pronti abbiamo deciso di utilizzare Python. Stiamo usando Python-C api per inviare/ricevere i dati tra c e python.Problema di concorrenza Python-C api

L'algoritmo funziona in questo modo: -

  1. Server riceve alcuni dati dal client, questi dati sono memorizzati in un dizionario creato nel c. Il dizionario viene creato utilizzando la funzione api PyDict_New(); da c. L'input è memorizzato come una coppia di valori chiave nel dizionario usando la funzione api PyDict_SetItemString();
  2. Successivamente, eseguiamo lo script python PyRun_SimpleString(); passare lo script come parametro. Questo script utilizza il dizionario creato in c. Nota, creiamo il dizionario creato in c, accessibile per lo script usando i metodi PyImport_AddModule(); e PyModule_AddObject();
  3. Memorizziamo il risultato dell'elaborazione dei dati nello script come una coppia di valori chiave nello stesso dizionario creato sopra. Il codice c può quindi semplicemente accedere alla variabile risultato (coppia chiave-valore) dopo che lo script è stato eseguito.

Il problema Il problema che stiamo affrontando è nel caso di richieste simultanee provenienti da diversi clienti. Quando arrivano più richieste da diversi client, tendiamo a fare eccezioni di conteggio dei riferimenti agli oggetti. Si prega di notare che per ogni richiesta che arriva per un utente, creiamo un dizionario indipendente solo per quell'utente. Per superare questo problema abbiamo incluso la chiamata a PyRun_SimpleString(); all'interno di PyEval_AcquireLock(); e PyEval_ReleaseLock() ;, ma facendo ciò si è verificato che l'esecuzione dello script fosse una chiamata bloccante. Quindi, se uno script richiede molto tempo per essere eseguito, tutti gli altri utenti sono in attesa di una risposta.

Potresti suggerire il miglior approccio possibile o dare indicazioni su dove stiamo andando male. Per favore, mandami un messaggio per maggiori informazioni.

Qualsiasi aiuto/guida sarà apprezzato.

risposta

1

Forse manca una delle chiamate indicate in this answer.

+0

Grazie per il riferimento Jane. Per inciso, avevo fatto chiamate a quelle funzioni, ma non funzionava ancora. – Will

1

Probabilmente dovresti leggere http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock Il tuo problema è spiegato nel primo paragrafo.

Quando acquisisci GIL, esegui la manipolazione diretta degli oggetti Python. La chiamata a PyRun_SimpleString gestirà internamente GIL e lo abbandonerà in operazioni di lunga durata o solo in tutte le istruzioni X. NON sarà veramente multi-threaded, comunque.

Edit:

È necessario acquisire il blocco ed è necessario per garantire che Python sa che è in un altro stato del thread:

// acquire the lock and switch thread state 
PyEval_AcquireLock(); 
PyThreadState_Swap(perThreadState); 

// execute some python code 
PyEval_SimpleString("print 123"); 

// clear the thread state and release the lock 
PyThreadState_Swap(NULL); 
PyEval_ReleaseLock(); 
+0

Ciao Tom, grazie per la risposta. Potresti per favore approfondire il fatto che "NON" sarà veramente multi-threaded?Intendi dire che gli script non possono mai essere eseguiti in parallelo? – Will

+0

C'è un blocco dell'interprete globale - solo un'istruzione bytecode python verrà eseguita in qualsiasi momento, indipendentemente dal numero di thread presenti. Funzioni a esecuzione prolungata come file aperti rilasciano temporaneamente il blocco mentre sono in esecuzione e l'interprete python rilascia periodicamente il blocco, ma in ultima analisi all'interno di un processo, bytecode python viene eseguito in serie. –

+0

Grazie per quello Tom. Apprezzo il tuo tempo per le risposte. Per favore conferma questo: Se PyRun_SimpleString è in esecuzione in 2 (o forse n) thread "c" separati, si prende cura del GIL stesso e quindi non ho bisogno di bloccare o bloccare prima di effettuare una chiamata a PyRun_SimpleString da qualsiasi thread. – Will

1

vi consiglio di indagare il modulo multiprocessing.

Problemi correlati