Executer une tache longue avec un thread

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je suis en train d'apprendre à utiliser django pour effectuer une petite interface web pour mon appli. C'est une application qui a un traitement long (environs 30 sec) et je lui indiquerai des paramètres grâce à une page web généré par django. Voici ce que j'ai essayé :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def long_process():
    call(["python3 testIperf.py 127.0.0.1 graphique.png"])

def contact(request):
    if request.method == 'POST':  # S'il s'agit d'une requê POST
        form = ContactForm(request.POST)  # Nous reprenons les donné

        if form.is_valid(): # Nous véfions que les donné envoyé sont valides

            # Ici nous pouvons traiter les donné du formulaire
            ip = form.cleaned_data["ip"]
            filename = form.cleaned_data["filename"]

            #call(["python3 testIperf.py", ip, filename])
            t = threading.Thread(target=long_process)
            t.start()

    else: # Si ce n'est pas du POST, c'est probablement une requê GET
        form = ContactForm()  # Nous crés un formulaire vide

    return render(request, 'testapp/contact.html', locals())

A des fins de test, je n'ai pas passé d'argument pour le moment. j'obtiens l'erreur suivante : FileNotFoundError: [Errno 2] No such file or directory: 'python3 testIperf.py 127.0.0.1 graphique.png'

Où dois-je placer mon fichier de script ?

Je suis débutant avec django et python, si vous pouvez me donner un petit coup de pouce, je vous en serais reconnaissant.

+0 -0

Ton cas d'utilisation est typiquement décrit ici :

  • la méthode à l'ancienne qui marchera mais ne sera pas nécessairement adapté à tout avec django :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def run_background(function):
    def decorator(*args, **kwargs):
        t = Thread(target = function, args=args, kwargs=kwargs)
        t.daemon = True
        t.start()
    return decorator

@run_background
def long_process():
   pass


def contact(request):
    if request.method == 'POST':  # S'il s'agit d'une requê POST
        form = ContactForm(request.POST)  # Nous reprenons les donné

        if form.is_valid(): # Nous véfions que les donné envoyé sont valides

            # Ici nous pouvons traiter les donné du formulaire
            ip = form.cleaned_data["ip"]
            filename = form.cleaned_data["filename"]
            long_process()

    else: # Si ce n'est pas du POST, c'est probablement une requê GET
        form = ContactForm()  # Nous crés un formulaire vide

    return render(request, 'testapp/contact.html', locals())
  • la méthode moderne mais parfois un peu overkill : utiliser django-celery

La fonction long_process fait quoi quand tu lances ton code directement avec python3 ? Une fenêtre apparaît et affiche le graphique ?

Tu n'as pas besoin de thread, si tu invoques ton script avec subprocess.Popen (cf. https://docs.python.org/3.5/library/subprocess.html#subprocess.Popen ), un nouveau processus indépendant est crée et ton programme a toujours la main.

1
2
3
4
5
>>> from subprocess import Popen
>>> Popen(['python3', 'script.py'])
<subprocess.Popen object at 0x103ae6828>
>>> # script.py tourne dans un nouveau processus
>>> # et nous avons toujours la main ici

Cependant, je ne comprends pas bien ce que tu souhaites faire, et je ne suis pas sûr que l'invocation soit la meilleure solution, mais il faudrait que tu nous en dises plus.

Attention, aussi, le GIL en Python marche plutôt bien depuis la version 3.2 pour ce qui est des actions I/O, mais ce n'est pas vraiment le cas pour les actions "CPU-bound". Si le rendu du graphique est coûteux en resources CPU (et je pense que c'est le cas, non ?), fais bien gaffe avec les threads.

+0 -0

Alors en fait le problème, c'est qu'il ne trouve pas le fichier actuellement, et je sais pas trop où je dois le placer dans l'arborescence django.

C'est un script qui appelle une commande bash, et fais quelques traitements sur les résultats obtenus (Des tests sur le réseau, donc ça peut prendre jusqu'à 30 secondes).

Ça, c'est du au fait que tu n'utilises pas call() de façon correcte : tu dois séparer la commande et les arguments, sinon il va essayer d'exécuter un script dont le nom serait "pythob test blabla".

Cependant, faire un appel externe n'est certainement pas la bonne façon d'exécuter un script Python en Python: tu devrais plutôt l'importer et le lancer dans un thread séparé.

Pour corriger mon problème, j'ai du : importer le répertoire où le script se situe au system path puis importer le script :

1
2
3
import sys
sys.path.append("/home/user/mywebsite/testapp/")
import testIperf

Suivit mes évolutions, je vais peut être utiliser subProcess.Popen().

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte