Python Tornado - hacer retorno puesto inmediatamente mientras que la función de trabajo asíncrono mantiene

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

  •  28-09-2019
  •  | 
  •  

Pregunta

así que tengo un manejador a continuación:

class PublishHandler(BaseHandler):

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

El problema que estoy enfrentando es que some_function () toma un poco de tiempo para ejecutar y me gustaría que la solicitud posterior para volver de inmediato cuando se le llama y para some_function () para ser ejecutado en otro hilo / proceso si es posible.

Estoy usando db Berkeley como base de datos y lo que estoy tratando de hacer es relativamente simple.

Tengo una base de datos de usuarios, cada uno con un filtro. Si el filtro coincide con el mensaje, el servidor enviará el mensaje al usuario. Estoy probando con miles de usuarios y por lo tanto sobre cada publicación de un mensaje a través de una solicitud de mensaje Se iteración a través de miles de usuarios para encontrar una coincidencia. Este es mi ingenua aplicación de hacer las cosas y por lo tanto mi pregunta. ¿Cómo puedo hacer esto mejor?

¿Fue útil?

Solución

podría ser capaz de lograr esto mediante el uso de método IOLoop de su add_callback este modo:

loop.add_callback(lambda: some_function(message))

Tornado ejecutará la devolución de llamada en la siguiente pasada IOLoop, que pueden (que tendría que profundizar en las tripas de Tornado de saber con certeza, o alternativamente probarlo) permitir que la solicitud se complete antes de que se código es ejecutado.

El inconveniente es que ese código de larga duración que ha escrito aún llevará tiempo para ejecutar, y esto puede terminar bloqueando otra solicitud. Eso no es ideal si usted tiene una gran cantidad de estas peticiones que entran a la vez.

La solución más infalible es ejecutar en un proceso o subproceso separado. El mejor manera con Python es el uso de un proceso, debido a la GIL (lo recomiendo mucho leer sobre que si usted no está familiarizado con él). Sin embargo, en una máquina de un solo procesador de la aplicación roscada funcionará igual de bien, y puede ser más sencillo de implementar.

Si usted va la ruta de rosca, se puede construir un buen módulo de "ejecutor asíncrono" con un mutex, un hilo, y una cola. Desproteger el módulo multiprocessing si quieres ir a la ruta de la utilización de un proceso separado.

Otros consejos

He intentado esto, y creo que la solicitud no se completa antes de que las devoluciones de llamada se llaman.

creo que un truco sucio sería llamar a dos niveles de add_callback, por ejemplo:.

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

Pero estos son en el mejor de los cortes. Estoy buscando una mejor solución en este momento, probablemente va a terminar con un poco de cola de mensajes o solución simple hilo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top