¿Cómo maneja Waitress las tareas concurrentes?

8

Estoy tratando de construir un servidor web Python usando Django y Waitress, pero me gustaría saber cómo Waitress maneja las solicitudes concurrentes y cuándo puede ocurrir el bloqueo .


Si bien la documentación de Waitress menciona que hay varios subprocesos de trabajo disponibles, no proporciona mucha información sobre cómo se implementan y cómo los afecta Python GIL (énfasis mío):

Cuando un canal determina que el cliente ha enviado al menos una solicitud HTTP válida completa, programa una "tarea" con un "despachador de subprocesos". El despachador de subprocesos mantiene un grupo fijo de subprocesos de trabajo disponibles para hacer el trabajo del cliente (de manera predeterminada, 4 subprocesos). Si un subproceso de trabajo está disponible cuando se programa una tarea, el subproceso de trabajo ejecuta la tarea. La tarea tiene acceso al canal y puede volver a escribir en el búfer de salida del canal. Cuando todos los hilos de trabajo están en uso , las tareas programadas esperarán en una cola para que un hilo de trabajo esté disponible.

Tampoco parece haber mucha información sobre Stackoverflow. De la pregunta "¿El trabajador asincrónico de greadread de Gunicorn es análogo a la camarera?" :

La camarera tiene un subproceso maestro asíncrono que almacena las solicitudes y almacena cada solicitud en uno de sus subprocesos de trabajo de sincronización cuando finaliza la E / S de la solicitud.


Estas declaraciones no abordan el GIL (al menos desde mi entendimiento) y sería genial si alguien pudiera dar más detalles sobre cómo funcionan los hilos de trabajo para Waitress. ¡Gracias!

FundidoMuffin
fuente
¿Conseguiste una solución para esto?
variable
@variable Desafortunadamente no. Al mirar brevemente el repositorio de github de la camarera , no parece que hayan hecho nada para evitar el GIL, aunque no puedo decirlo con certeza. Por el momento, mi equipo se queda con Waitress ya que nuestra aplicación no requiere un nivel de concurrencia demasiado alto.
MoltenMuffins
Al usar el servidor de matraz de desarrollo predeterminado, podemos establecer el número de procesos usando werkzeug.palletsprojects.com/en/1.0.x/serving/… - ¿esto no existe en la camarera?
variable
Sí, se puede configurar el número de trabajadores, pero esto no dice nada de su comportamiento de bloqueo
MoltenMuffins
Si un trabajador significa un proceso independiente, entonces esto significa que cada proceso tiene su propio intérprete de Python. ¿no es así?
variable

Respuestas:

1

Así es como funcionan generalmente los servidores asincrónicos controlados por eventos:

  • Inicie un proceso y escuche las solicitudes entrantes. La utilización de la API de notificación de eventos del sistema operativo hace que sea muy fácil atender a miles de clientes desde un solo hilo / proceso.
  • Como solo hay un proceso que administra todas las conexiones, no desea realizar ninguna tarea lenta (o de bloqueo) en este proceso. Porque entonces bloqueará el programa para cada cliente.
  • Para realizar tareas de bloqueo, el servidor delega las tareas a "trabajadores". Los trabajadores pueden ser hilos (que se ejecutan en el mismo proceso) o procesos separados (o subprocesos). Ahora el proceso principal puede seguir sirviendo a los clientes mientras los trabajadores realizan las tareas de bloqueo.

¿Cómo maneja Waitress las tareas concurrentes?

Casi de la misma manera que acabo de describir arriba. Y para los trabajadores crea hilos, no procesos.

cómo los afecta Python GIL

La camarera usa hilos para los trabajadores. Entonces, sí, se ven afectados por GIL en el sentido de que no son realmente concurrentes, aunque parecen serlo. "Asíncrono" es el término correcto.

Los subprocesos en Python se ejecutan dentro de un solo proceso, en un solo núcleo de CPU, y no se ejecutan en paralelo. Un hilo adquiere el GIL por un período de tiempo muy pequeño y ejecuta su código y luego el GIL es adquirido por otro hilo.

Pero dado que el GIL se libera en la E / S de la red, el proceso padre siempre adquirirá el GIL siempre que haya un evento de red (como una solicitud entrante) y de esta manera puede estar seguro de que el GIL no afectará las operaciones vinculadas a la red ( como recibir solicitudes o enviar respuestas).

Por otro lado, los procesos de Python son realmente concurrentes: pueden ejecutarse en paralelo en múltiples núcleos. Pero Waitress no usa procesos.

¿Deberías estar preocupado?

Si solo está realizando pequeñas tareas de bloqueo como lectura / escritura de bases de datos y solo atiende a unos pocos cientos de usuarios por segundo, entonces el uso de hilos no es realmente tan malo.

Para servir a un gran volumen de usuarios o realizar tareas de bloqueo de larga duración, puede buscar colas de tareas externas como Celery . Esto será mucho mejor que generar y gestionar procesos usted mismo.

xyres
fuente
¿Es mejor usar un servidor de aplicaciones basado en procesos para procesar más solicitudes?
variable
@variable Si está realizando tareas vinculadas a la CPU (también conocidas como tareas de bloqueo) como cálculos pesados, entonces, sí, usar trabajadores de proceso es mejor. Pero hay proyectos como Celery que lo ayudan a ejecutar tareas de bloqueo en "colas de tareas" separadas. Por lo tanto, no importa qué tipo de servidor de aplicaciones esté utilizando. Pero solo para realizar tareas vinculadas a la red (como esperar solicitudes de clientes o obtener datos de API de terceros), entonces no necesita trabajadores.
xyres
@variable Y si por servidor "basado en procesos" se refería a un servidor que crea un nuevo proceso para cada solicitud, entonces no, esa es la forma menos escalable. La forma más eficiente (y común) es lo que describí en la parte superior de la respuesta: atender todas las solicitudes de un solo proceso principal y delegar tareas de bloqueo a los trabajadores (subprocesos o subprocesos).
xyres
Por "delegar tareas de bloqueo a los trabajadores (subprocesos o subprocesos)", ¿se refiere a apio?
variable
@variable Usted mismo puede mantener un conjunto de subprocesos en su programa y pasarles las tareas de bloqueo. Para proyectos más pequeños, este enfoque está bien. El apio le dará la ventaja de una fácil escalabilidad. Puede ejecutarlo fácilmente en un solo servidor o en un grupo de servidores, según sus necesidades. Sin embargo, para proyectos más pequeños puede ser una exageración. Puede cambiar a Apio si lo necesita.
xyres