2013-08-24 5 views
21

Certaines fonctions doivent s'exécuter de manière asynchrone sur le serveur Web. L'envoi de courriels est un exemple classique. Quelle est la meilleure façon (ou la plus pythonique) d'écrire une fonction décorateur pour exécuter une fonction de manière asynchrone?Multithreading pour Python Django

Ma configuration est une commune un: Python 2.4.7, Django 1.4, gunicorn 0.17.2

Par exemple, voici un début:

from threading import Thread 

def postpone(function): 
    def decorator(*args, **kwargs): 
     t = Thread(target = function, args=args, kwargs=kwargs) 
     t.daemon = True 
     t.start() 
    return decorator 

utilisation souhaitée:

@postpone 
def foo(): 
    pass #do stuff 
+0

Regardez ce poste trop http://stackoverflow.com/questions/573618/django -set-up-a-schedule-job. Pour une tâche planifiée, choisissez une solution basée sur cron. Tâche planifiée, les tâches asynchrones choisissent Céleri. Je commence par https://github.com/tivix/django-cron avant de migrer vers Celery récemment. –

+5

Merci pour toutes les réponses à ce jour, mais le céleri nécessite un peu de frais généraux (installation de l'application, en créant un DB pour cela). Donc, alors que Céleri est une solution, il ne répond pas à ma question sur l'écriture d'un décorateur autonome pour multithread une fonction. – tomcounsell

Répondre

35

J'ai posté la question ci-dessus il ya 18 mois. Depuis lors, j'ai continué à utiliser cette implémentation à grande échelle et en production sans problème.

définition Décorateur:

from threading import Thread 
def postpone(function): 
    def decorator(*args, **kwargs): 
    t = Thread(target = function, args=args, kwargs=kwargs) 
    t.daemon = True 
    t.start() 
    return decorator 

Exemple d'utilisation:

@postpone 
def foo(): 
    #do stuff 

Au fil du temps, la pile a mis à jour et la transition sans échec.

À l'origine Python 2.4.7, Django 1.4, Gunicorn 0.17.2, maintenant Python 2.4.7, Django 1.9, Waitress 0.8.9.

Si vous utilisez toutes les transactions de base de données, Django va créer une nouvelle connexion et cela doit être fermé manuellement:

from django.db import connection 

@postpone 
def foo(): 
    #do stuff 
    connection.close() 
+1

Je lance cette même implémentation en production sans problèmes et la meilleure partie est qu'elle fonctionne avec uwsgi sans aucun problème majeur de performance – Deepak

+0

Limitez-vous le nombre de threads générés? Est-il possible que quelqu'un enfonce votre code? – CadentOrange

+0

Je ne l'ai pas utilisé dans des scénarios où plus de quelques threads peuvent être créés dans une seule requête Web. Je n'ai aucune raison de lancer une fonction qui utilise ce décorateur dans une boucle. Il vaudrait mieux envelopper simplement cette logique dans une seule fonction qui s'exécute dans un thread supplémentaire. L'objectif ici est de différer tout traitement qui n'est pas essentiel pour renvoyer la requête Web. – tomcounsell

3

La méthode la plus courante pour effectuer un traitement asynchrone dans Django consiste à utiliser Celery et django-celery.

13

Celery est une file d'attente/file d'attente de tâches asynchrones. C'est bien documenté et parfait pour ce dont vous avez besoin. Je vous suggère de commencer here