Python halcón y operaciones asíncronas.

Estoy escribiendo una API usando la combinación python3 + falcon.

Hay muchos lugares en los métodos donde puedo enviar una respuesta a un cliente, pero debido a un código pesado que hace DB, operaciones de E / S, etc., tiene que esperar hasta que finalice la parte pesada.

Por ejemplo:

class APIHandler: def on_get(self, req, resp): response = "Hello" #Some heavy code resp.body(response) 

Podría enviar “Hola” en la primera línea de código. Lo que quiero es ejecutar el código pesado en segundo plano y enviar una respuesta, independientemente de cuándo finalice la parte pesada.

Falcon no tiene capacidades asíncronas integradas, pero mencionan que se puede usar con algo como gevent. No he encontrado ninguna documentación de cómo combinar esos dos.

Uso apio para trabajos relacionados con async. No sé sobre gevent. Eche un vistazo a este http://celery.readthedocs.org/en/latest/getting-started/introduction.html

Las bibliotecas de los clientes tienen un soporte variable para las operaciones asíncronas, por lo que la decisión a menudo se reduce a qué enfoque asíncrono es mejor admitido por sus clientes de back-end particulares, combinados con el servidor WSGI que le gustaría usar. Vea también a continuación algunas de las opciones más comunes …

Para las bibliotecas que no admiten un modelo de interacción asíncrona, ya sea de forma nativa o mediante algún tipo de mecanismo de subclasificación, las tareas se pueden delegar a un grupo de subprocesos. Y, especialmente para las tareas de larga duración (es decir, del orden de varios segundos o minutos), Celery no es una mala elección.

Una breve encuesta de algunas de las opciones asíncronas más comunes para aplicaciones WSGI (y Falcon ):

  • Retorcido. Favorece un estilo asíncrono explícito y es probablemente la opción más madura. Para la integración con un marco WSGI como Falcon, hay twisted.web.wsgi y crochet .
  • asyncio. Toma prestadas muchas ideas de Twisted, pero aprovecha las características del lenguaje Python 3 para proporcionar una interfaz más limpia. A largo plazo, esta es probablemente la opción más limpia, pero necesita una evolución de la interfaz WSGI (vea también la extensión de PICK-3333 como un posible enfoque). El ecosistema de asyncio es relativamente joven en el momento de este escrito; la comunidad todavía está experimentando con una amplia variedad de enfoques en torno a interfaces, patrones y herramientas.
  • eventlet Favorece un estilo implícito que busca hacer que el código asíncrono parezca sincrónico. Una forma en que Eventlet hace esto es mediante la aplicación de parches de mono en los módulos de E / S en la biblioteca estándar. A algunas personas no les gusta este enfoque porque enmascara el mecanismo asíncrono, lo que dificulta la depuración de los casos perimetrales.
  • gevent Similar a eventlet, aunque un poco más moderno. Tanto uWSGI como Gunicorn son compatibles con los tipos de trabajo de gevent que parchean con mono la biblioteca estándar.

Finalmente, puede ser posible extender Falcon para que soporte de forma nativa twisted.web o asyncio (ala aiohttp), pero no creo que nadie lo haya intentado todavía.

Creo que hay dos enfoques diferentes aquí:

  1. Un administrador de tareas (como el apio)
  2. Una implementación asíncrona (como gevent)

Lo que logres con cada uno de ellos es diferente. Con Celery, lo que puede hacer es ejecutar todo el código que necesita para calcular la respuesta de forma sincrónica y luego ejecutar en segundo plano cualquier otra operación (como guardar en registros). De esta manera, la respuesta debería ser más rápida.

Con gevent, lo que logras, es ejecutar en paralelo diferentes instancias de tu controlador. Por lo tanto, si tiene una sola solicitud, no verá ninguna diferencia en el tiempo de respuesta, pero si tiene miles de solicitudes simultáneas, el rendimiento será mucho mejor. La razón de esto, es que sin gevent, cuando su código ejecuta una operación IO, bloquea la ejecución de ese proceso, mientras que con gevent, la CPU puede continuar ejecutando otras solicitudes mientras la operación IO espera.

Configurar gevent es mucho más fácil que configurar apio. Si está utilizando gunicorn, simplemente instale gevent y cambie el tipo de trabajador a gevent. Otra ventaja es que puede paralelizar cualquier operación que se requiera en la respuesta (como extraer la respuesta de una base de datos). En Apio, no puede usar la salida de la tarea de Apio en su respuesta.

Lo que recomendaría es comenzar usando gevent y considerar agregar Celery más tarde (y tener ambos) si:

  • La salida de la tarea que procesará con apio no se requiere en la respuesta.
  • Tiene una máquina diferente para sus tareas de apio, o el uso de su servidor tiene algunos picos y tiempo de inactividad (si su servidor está al 100% todo el tiempo, no obtendrá nada bueno de usar Celery)
  • La cantidad de trabajo que harán tus tareas de apio, vale la pena la sobrecarga de usar apio.