¿Cuántas solicitudes concurrentes recibe un solo proceso de Flask?

138

Estoy creando una aplicación con Flask, pero no sé mucho sobre WSGI y su base HTTP, Werkzeug. Cuando comienzo a servir una aplicación Flask con gunicorn y 4 procesos de trabajo, ¿significa que puedo manejar 4 solicitudes concurrentes?

Me refiero a solicitudes concurrentes, y no solicitudes por segundo o cualquier otra cosa.

Carson
fuente

Respuestas:

183

Al ejecutar el servidor de desarrollo, que es lo que obtienes al ejecutar app.run(), obtienes un solo proceso síncrono, lo que significa que a lo sumo se procesa 1 solicitud a la vez.

Al colocar Gunicorn frente a él en su configuración predeterminada y simplemente aumentar el número de --workers, lo que obtienes es esencialmente una serie de procesos (administrados por Gunicorn) que se comportan como el app.run()servidor de desarrollo. 4 trabajadores == 4 solicitudes concurrentes. Esto se debe a que Gunicorn usa su synctipo de trabajador incluido de forma predeterminada.

Es importante tener en cuenta que Gunicorn también incluye trabajadores asincrónicos, a saber, eventlety gevent(y también tornado, pero parece que es mejor usarlo con el marco Tornado). Al especificar uno de estos trabajadores asincrónicos con la --worker-classbandera, lo que obtienes es que Gunicorn gestione una serie de procesos asincrónicos, cada uno de los cuales gestiona su propia concurrencia. Estos procesos no usan hilos, sino corutinas. Básicamente, dentro de cada proceso, todavía solo puede estar sucediendo 1 cosa a la vez (1 subproceso), pero los objetos se pueden 'pausar' cuando están esperando que finalicen los procesos externos (piense en las consultas de la base de datos o en las E / S de la red).

Esto significa que si está utilizando uno de los trabajadores asincrónicos de Gunicorn, cada trabajador puede manejar muchas más de una solicitud a la vez. El número máximo de trabajadores depende de la naturaleza de su aplicación, su entorno, el hardware en el que se ejecuta, etc. Se pueden encontrar más detalles en la página de diseño de Gunicorn y notas sobre cómo funciona gevent en su página de introducción.

Ryan Artecona
fuente
44
Gunicorn ahora admite hilos "reales" desde la versión 19. Vea esto y esto .
Filipe Correia
2
¿Cómo se hace un seguimiento de qué recursos se comparten (y cómo) y cuáles están completamente separados entre hilos / procesos? Por ejemplo, ¿cómo manejaría una situación en la que quiero compartir una gran estructura de datos entre varios procesos manejados por Gunicorn y utilizados en los controladores de Flask?
Johann Petrak
Lo que le preguntas a @Johsm es como preguntar cómo compartir datos entre diferentes procesos dentro del sistema operativo. La respuesta a eso puede responder a su pregunta, debe usar almacenamiento externo ya que los procesos no comparten su memoria con otros procesos. Gunicorn está aquí solo para utilizar arquitecturas de CPU de multiprocesamiento, pero no maneja esos problemas.
adkl
¿Qué hay de Eva? ¿Esto también es válido para Eva?
Eswar
2
el servidor de desarrollo de matraces usa hilos de forma predeterminada desde v1.0 ( github.com/pallets/flask/pull/2529 )
hychou
40

Actualmente hay una solución mucho más simple que las que ya se ofrecen. Al ejecutar su aplicación, solo tiene que pasar el threaded=Trueparámetro a la app.run()llamada, como:

app.run(host="your.host", port=4321, threaded=True)

Otra opción según lo que podemos ver en los documentos de werkzeug , es usar el processesparámetro, que recibe un número> 1 que indica el número máximo de procesos concurrentes para manejar:

  • Enhebrado: ¿el proceso debe manejar cada solicitud en un hilo separado?
  • procesos: si es mayor que 1, maneje cada solicitud en un nuevo proceso hasta este número máximo de procesos concurrentes.

Algo como:

app.run(host="your.host", port=4321, processes=3) #up to 3 processes

Más información sobre el run()método aquí , y la publicación del blog que me llevó a encontrar la solución y las referencias de la API.


Nota: en los documentos de Flask sobre los run()métodos, se indica que se desaconseja su uso en un entorno de producción porque ( cita ): "Aunque es liviano y fácil de usar, el servidor incorporado de Flask no es adecuado para la producción, ya que no escala bien ".

Sin embargo, apuntan a su página de Opciones de implementación para ver las formas recomendadas de hacer esto cuando van a la producción.

DarkCygnus
fuente
55
Gracias por la info. Es importante tener en cuenta que el documento para ejecutar indica que no debe usarse en un entorno de producción que indique que no cumple con los requisitos de seguridad o rendimiento.
Coffee_fan
1
@ Café_fan tienes razón. Incluso en la última versión 1.1.x, desalientan eso y, en cambio, sugieren revisar su página en Opciones de implementación cuando vayan a producción. Incluyendo su valiosa observación en la respuesta :)
DarkCygnus
33

Flask procesará una solicitud por hilo al mismo tiempo. Si tiene 2 procesos con 4 hilos cada uno, son 8 solicitudes simultáneas.

Flask no genera ni gestiona hilos o procesos. Esa es la responsabilidad de la puerta de enlace WSGI (por ejemplo, gunicorn).

jd.
fuente
9

No, definitivamente puedes manejar más que eso.

Es importante recordar que en el fondo, suponiendo que esté ejecutando una máquina de un solo núcleo, la CPU solo ejecuta una instrucción * a la vez.

Es decir, la CPU solo puede ejecutar un conjunto muy limitado de instrucciones, y no puede ejecutar más de una instrucción por marca de reloj (muchas instrucciones incluso toman más de 1 marca).

Por lo tanto, la mayor concurrencia de la que hablamos en informática es la concurrencia de software. En otras palabras, hay capas de implementación de software que abstraen de nosotros la CPU de nivel inferior y nos hacen pensar que estamos ejecutando código simultáneamente.

Estas "cosas" pueden ser procesos, que son unidades de código que se ejecutan simultáneamente en el sentido de que cada proceso piensa que se está ejecutando en su propio mundo con su propia memoria no compartida.

Otro ejemplo son los hilos, que son unidades de código dentro de los procesos que también permiten la concurrencia.

La razón por la cual sus 4 procesos de trabajo podrán manejar más de 4 solicitudes es porque dispararán hilos para manejar más y más solicitudes.

El límite de solicitud real depende del servidor HTTP elegido, E / S, SO, hardware, conexión de red, etc.

¡Buena suerte!

* las instrucciones son los comandos muy básicos que puede ejecutar la CPU. ejemplos: sumar dos números, saltar de una instrucción a otra

usuario1094786
fuente
1
¿Es gunicorn engendrando los hilos o el matraz? No encontré evidencia que apoyara ninguna de las posibilidades.
jd.
1
Claro, entiendo eso sobre los procesos, pero la respuesta dice que se generan más hilos según sea necesario. Eso es de lo que me gustaría tener confirmación.
jd.
44
"En el fondo, suponiendo que esté ejecutando una máquina de un solo núcleo, la CPU solo ejecuta una instrucción * a la vez" Esto no es correcto en las máquinas modernas. La mayoría de las CPU modernas están canalizadas y superescalares , donde incluso un solo núcleo tiene múltiples unidades de ejecución y un decodificador de instrucciones que convierte el "código de máquina" visto desde el lado del software en las microoperaciones de hardware reales que se envían a las unidades de ejecución individuales.
Michael Geary
1
Para aclarar, en el pasado, las CPU realmente ejecutaban directamente las instrucciones numéricas en un ejecutable: el código de la máquina. Cada referencia de CPU tenía un cuadro de tiempo de instrucciones que mostraba cuántos ciclos de reloj tomó cada instrucción, incluidas las referencias de memoria. Entonces, podría sumar los tiempos para saber cuánto tiempo tomaría cualquier fragmento de código. Las CPU modernas no son así en absoluto. Una excepción interesante es el BeagleBone que tiene un procesador ARM superescalar moderno y dos procesadores "PRU" anticuados con tiempos de instrucción fijos.
Michael Geary
1
Y para aclarar que , cuando dije "moderno", lo estaba usando como una abreviatura para procesadores como chips ARM / Intel / AMD: canalizados, superescalares, etc. Por supuesto, también hay procesadores modernos que funcionan a la antigua usanza con temporización fija por instrucción, como las PRU BeagleBone que mencioné y varios microcontroladores nuevos. (¡Y ahora de vuelta a Gunicorn!)
Michael Geary