Python Tornado - facendo ritorno POST immediatamente mentre la funzione asincrona continua a lavorare

StackOverflow https://stackoverflow.com/questions/3869421

  •  28-09-2019
  •  | 
  •  

Domanda

quindi ho un gestore di seguito:

class PublishHandler(BaseHandler):

    def post(self):
        message = self.get_argument("message")
        some_function(message)
        self.write("success")

Il problema che sto affrontando è che una_qualche_funzione () richiede un certo tempo per l'esecuzione e vorrei richiesta POST per tornare subito quando viene chiamato e per una_qualche_funzione () per essere eseguito in un altro thread / processo, se possibile.

sto usando Berkeley DB come database e quello che sto cercando di fare è relativamente semplice.

Ho un database di utenti ognuno con un filtro. Se il filtro corrisponde al messaggio, il server invierà il messaggio per l'utente. Attualmente sto testando con migliaia di utenti e, quindi, su ogni pubblicazione di un messaggio tramite una richiesta POST è iterazione attraverso migliaia di utenti per trovare una corrispondenza. Questa è la mia ingenua implementazione di fare le cose e quindi la mia domanda. Come posso fare questo meglio?

È stato utile?

Soluzione

Si potrebbe essere in grado di ottenere questo risultato utilizzando il metodo IOLoop del add_callback in questo modo:

loop.add_callback(lambda: some_function(message))

Tornado eseguirà la richiamata nel prossimo passaggio IOLoop, che possono (avrei dovuto scavare in budella di Tornado di sapere per certo, o, in alternativa testarlo) consentire la richiesta di completare prima che il codice viene eseguito.

Lo svantaggio è che che il codice a lunga corsa che hai scritto sarà ancora tempo per l'esecuzione, e questo può finire per bloccare un'altra richiesta. Questo non è l'ideale se si dispone di un sacco di questi le richieste che arrivano in una sola volta.

La soluzione più infallibile è eseguire in un thread o processo separato. Il migliore strada con Python è quello di utilizzare un processo, a causa della GIL (mi raccomando la lettura su che se non hai familiarità con esso). Tuttavia, su una macchina a singolo processore all'attuazione filettato funziona altrettanto bene, e può essere più semplice da implementare.

Se avete intenzione il percorso filettato, si può costruire un modulo bel "async esecutore" con un mutex, un filo, e una coda. Estrai il modulo multiprocessing se si vuole andare l'itinerario di utilizzare un processo separato.

Altri suggerimenti

Ho provato questo, e credo che la richiesta non viene completata prima che i callback sono chiamati.

Credo che un hack sporco sarebbe quello di chiamare due livelli di add_callback, per esempio:.

  def get(self):
    ...
    def _defered():
      ioloop.add_callback(<whatever you want>)
    ioloop.add_callback(_defered)
    ...

Ma questi sono hack al meglio. Sto cercando una soluzione migliore in questo momento, probabilmente finirà con un po 'di coda di messaggi o una soluzione semplice filo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top