2010-12-26 6 views
7

J'ai un tas de demandes Django qui exécute des calculs mathématiques (écrit en C et exécuté par un module Cython) qui peut prendre une quantité indéterminée (de l'ordre de 1 seconde) de temps à exécuter. De plus, les requêtes n'ont pas besoin d'accéder à la base de données et sont toutes indépendantes les unes des autres et de Django.Django traitement asynchrone

À l'heure actuelle tout est synchrone (en utilisant Gunicorn avec sync types de travailleurs), mais je voudrais faire de ce asynchrone et non bloquant. En bref, je voudrais faire quelque chose:

  1. Recevoir la demande AJAX
  2. Allouer tâche à un travailleur disponible (sans bloquer la principale application web Django)
  3. travailleur exécute la tâche dans une certaine quantité de temps inconnue
  4. Django renvoie le résultat du calcul (une liste de chaînes) comme JSON chaque fois que la tâche est terminée

Je suis très nouveau à Django asynchrone, et donc ma question est quelle est la meilleure pile fo r faisant ceci.

Est-ce ce genre de processus quelque chose d'une file d'attente des tâches est bien adapté pour? Quelqu'un pourrait-il recommander Tornado + Céleri + RabbitMQ, ou peut-être autre chose?

Merci d'avance!

+0

Que faites-vous avec les résultats des calculs? – sdolan

+0

Renvoyez le résultat (en JSON) au navigateur de l'utilisateur. –

Répondre

14

Céleri serait parfait pour cela. Puisque ce que vous faites est relativement simple (lire: vous n'avez pas besoin de règles complexes sur la manière dont les tâches doivent être routées), vous pouvez probablement utiliser le backend Redis, ce qui signifie que vous n'avez pas besoin de setup/configure RabbitMQ (qui, selon mon expérience, est plus difficile).

J'utilise Redis avec le plus une version dev de Céleri, et voici les bits pertinents de ma config:

 
# Use redis as a queue 
BROKER_BACKEND = "kombu.transport.pyredis.Transport" 
BROKER_HOST = "localhost" 
BROKER_PORT = 6379 
BROKER_VHOST = "0" 

# Store results in redis 
CELERY_RESULT_BACKEND = "redis" 
REDIS_HOST = "localhost" 
REDIS_PORT = 6379 
REDIS_DB = "0" 

J'utilise également django-celery, ce qui rend l'intégration avec Django heureux.

Commentaire si vous avez besoin de conseils plus spécifiques.

+1

De plus, je n'ai eu aucun problème avec l'utilisation de 'gevent' + patch de singe avec Celery, donc si vous utilisez le 'gevent' gunicorn worker et monkeypatch' celery', tout devrait juste être asynchrone comme par magie. –

+0

Merci pour le conseil. J'ai essayé d'utiliser 'gevent' workers + patch de singe dans le passé, mais il ralentit mon application à une exploration. Je suppose que c'est dû à ma connexion bloquante avec MySQL. Aurais-je besoin de passer à une base de données différente? –

+0

Désolé, je n'ai pas travaillé avec 'gevent' et d'autres DBs, donc je ne pourrais pas dire. Peut-être poster une autre question demandant à ce sujet? –

0

Puisque vous envisagez de le rendre asynchrone (probablement en utilisant quelque chose comme gevent), vous pouvez également envisager de créer un service web backend threadé/forké pour le travail de calcul. Le serveur frontal async peut gérer tout le travail léger, obtenir des données à partir de bases de données qui conviennent pour async (redis ou mysql avec un pilote spécial), etc. Quand un calcul doit être fait, le serveur frontal peut afficher tout Entrez les données dans le serveur principal et récupérez le résultat lorsque le serveur principal a terminé de le calculer.

Étant donné que le serveur frontal est asynchrone, il ne bloquera pas en attendant les résultats. L'avantage de cela, par opposition à l'utilisation de céleri, est que vous pouvez retourner le résultat au client dès qu'il devient disponible.

client browser <> async frontend server <> backend server for computations 
Questions connexes