Recientemente estoy usando Django para programar mi interfaz web para mi "motor de computación científica".
Envuelvo el "motor de computación" como un módulo de python y lo llamo dentro de Django Framework.
La función de compute() del "motor" tarda varios minutos en ejecutarse (uso ajax para activarlo), al mismo tiempo, dejo que el front-end haga una llamada ajax adicional cada 0,5 segundos para actualizar el estado de la CPU y la memoria a el front-end. Pero encuentro que el servidor no responde a la llamada ajax adicional hasta que finaliza el compute() .
Después de buscar, creo que podría usar la idea de multithreading múltiples o asynchronous
así que hago la función en views.py como a continuación.
def submit(request): #some prepare ........ # call the engine t = Thread(target = compute) t.start() return HttpResponse("started")
Pero el sistema aún no responde a mi llamada ajax adicional hasta que finaliza el compute() (El "motor" solo usa alrededor del 20% de la CPU, por lo que queda mucha potencia informática).
Soy un novato en la programación de back-end, no estoy seguro de cómo Django o el servidor de back-end manejan la solicitud internamente. Muchas gracias si alguien me puede dar alguna pista sobre cómo manejar esta situación.
Nunca es una buena idea iniciar hilos desde puntos de vista como ese.
La forma más común de resolver esto es delegar el trabajo a un trabajador/proceso separado. Además de django, tiene otro proceso de python que busca trabajo.
Puede mantenerlo simple y hacer que la vista de Django almacene información sobre el trabajo que debe realizarse en algún formato en el disco o en una base de datos (esta sería la cola de trabajo). Luego, el proceso de trabajo se ejecutará en un ciclo verificando el trabajo disponible cada N segundos. Aumente la cantidad de trabajadores/procesos para agregar más poder de cómputo (limitado por su hardware, por supuesto)
La solicitud http que crea la solicitud de trabajo puede devolver un job_id que el usuario puede consultar para obtener el estado del trabajo. ¿El trabajo está pendiente/en progreso/terminado? Entonces, ¿tal vez el usuario también pueda obtener el resultado del trabajo o incluso metadatos como la duración y los registros?
También existen marcos para resolver problemas como este, como Celery y django-channels. El apio es probablemente más fácil para empezar, pero podría ser excesivo para lo que estás tratando de hacer.
La ventaja de usar trabajadores como este es que puede tener una API REST muy liviana en el frente y puede aumentar la cantidad de trabajadores, posiblemente en varios servidores a medida que aumenta la demanda.
Finalmente resolví este problema usando el subprocess de python
Hago mi código de "computación" en un archivo separado y uso Popen para llamarlo.
from subprocess import Popen def submit(request): #some prepare ........ # call the engine p = Popen(["python", "compute.py", <arguments>]) return HttpResponse("started")
Sin embargo, como se sugiere, el subprocess no es una práctica muy buena y segura. Esta solución es fácil de realizar, pero intentaré convertir el back-end al worker mode usando Celery o django-channels como sugirió @Grimmy.