2012-11-08 26 views
5

Sto creando un'applicazione Web che utilizza Python + Tornado che fondamentalmente serve i file agli utenti. Non ho databaseChiamata asincrona Tornado a una funzione

I file vengono prelevati e pubblicati direttamente se disponibili o generati al volo in caso contrario.

Desidero che i client vengano offerti in modo asincrono, poiché alcuni file potrebbero essere già disponibili, mentre altri devono essere generati (quindi è necessario attendere e non voglio che blocchino altri utenti).

Ho una classe che gestisce il prelievo o la generazione di file, e ho solo bisogno di chiamarlo da Tornado.

Qual è il modo migliore (più efficiente su CPU e RAM) per ottenerlo? Dovrei usare una discussione? Un processo secondario? Un semplice gen.Task like this one?

Inoltre, vorrei che la mia implementazione funzionasse con Google App Engines (penso che non consentano la generazione di processi secondari?).

Sono relativamente nuovo al servizio web asincrono, quindi qualsiasi aiuto è benvenuto.

+1

Il gen.Task funzionerà bene. Se il tuo file che sta generando/generando codice non può giocare bene in quel modo, un thread funzionerà correttamente. Puoi anche generare più processi, ma non conosco le limitazioni su Google App Engine. – sean

+0

Grazie per la risposta. Sai anche come andrà a finire se genererò più gen.Task? Voglio dire, il mio ** metodo di istanza ** può essere abbastanza costoso e richiede molto tempo, se questo metodo viene chiamato più volte da più utenti, cosa succederà?Tutti i metodi eseguiranno asincrona in parallelo o i metodi successivi attenderanno prima che i precedenti terminino per primi? (nota che ho una singola istanza della mia classe che uso in tutta la mia intera applicazione) – gaborous

+1

Totalmente oscurato, dovrebbe andare bene, ma indipendentemente dalla tua soluzione sarebbe un problema con un sacco di thread a prescindere. Se questa è una preoccupazione, prova a esaminare la suddivisione in processi separati o l'esecuzione di più istanze dietro un bilanciamento del carico. – sean

risposta

10

ho trovato le risposte alle mie domande: L'esempio genTask è davvero il modo migliore per attuare una chiamata asincrona, ed è dovuto al fatto che l'esempio fa uso di un Python coroutine, che io didn' t capire a prima vista perché ho pensato resa è stato utilizzato solo per restituire un valore per i generatori.

Esempio concreto:

class MyHandler(tornado.web.RequestHandler): 

    @asynchronous 
    @gen.engine 
    def get(self): 
     response = yield gen.Task(self.dosomething, 'argument') 

Ciò che è importante è la combinazione di due cose:

  • resa, che di fatto genera un coroutine (o pseudo-filo, che è molto efficiente e fatto per essere altamente concorrente-friendly). http://www.python.org/dev/peps/pep-0342/

  • gen.Task() che è una funzione non bloccante (asincrona), perché se si depongono le uova un coroutine su una funzione di blocco, non sarà asincrona. gen.Task() viene fornito da Tornado, in particolare per lavorare con la sintassi di coroutine di Python. Ulteriori informazioni: http://www.tornadoweb.org/documentation/gen.html

Quindi un esempio canonico di una chiamata asincrona in Python utilizzando coroutine:

response = yield non_blocking_func(**kwargs) 
+1

Anche qui c'è un altro post in cui sono dettagliati sia la coroutine che la vecchia implementazione callback: http://stackoverflow.com/questions/8812715/using-a-simple-python-generator-as-a-co-routine-in -a-tornado-async-handler? RQ = 1 – gaborous

1

Ora Documentation hanno soluzione.

semplice esempio:

import os.path 
import tornado.web 
from tornado import gen 

class MyHandler(tornado.web.RequestHandler): 

    @gen.coroutine 
    def get(self, filename): 
     result = yield self.some_usefull_process(filename) 
     self.write(result) 

    @gen.coroutine 
    def some_usefull_process(self, filename): 
     if not os.path.exists(filename): 
      status = yield self.generate_file(filename) 
      result = 'File created' 
     else: 
      result = 'File exists' 

     raise gen.Return(result) 

    @gen.coroutine 
    def generate_file(self, filename): 
     fd = open(filename, 'w') 
     fd.write('created') 
     fd.close() 
Problemi correlati