Forum Programmation.python Threading : comment faire un sys.stdout sur plusieurs lignes (ou identifier chaque thread) ?

Posté par  .
Étiquettes : aucune
0
13
juil.
2009
Bonjour à tous !

Pour apprendre le Python, je développe un petit gestionnaire de téléchargements sans prétention. J'utilise le module threading pour télécharger plusieurs fichiers à la fois et sys.stdout.write pour afficher l'évolution du téléchargement en cours.

Mais comme plusieurs téléchargements sont en concurrence, la progression d'un thread est immédiatement remplacée par l'état du thread suivant. C'est illisible. Je souhaite pouvoir afficher la progression de tous les téléchargements en même temps, en utilisant plusieurs lignes.

Comment procéder ?
Je crois que la solution passe par des print, mais comment identifier le dernier thread en cours et vider l'affichage ?
(pour être complet, arriver à identifier chaque thread me permettrait aussi de les lier à une barre de progression en gtk/glade, si vous pouviez me dépanner là dessus ça serait génial).

Par avance un grand MERCI pour votre aide !

Le code se présente comme ceci : http://pastebin.com/m5f17800e
  • # Il faut protéger les ressources partagées

    Posté par  . Évalué à 2.

    Lorsqu'on fait de la programmation multi-thread, il faut toujours faire bien attention à identifier et protéger les ressources partagées entre plusieurs threads.

    Dans ton cas, sys.stdout, est une ressources partagée qu'il faut protéger au moyen d'un mutex. Avec le module threading de python, c'est très simple, il te faut une variable partagée entre tous les threads et que tu lock dès que tu veux afficher quelquechose. Par exemple :

    #La variable partagée entre tous les threads
    stdoutlock = threading.Lock()
    [...]
    #lorsqu'on veut afficher :
    try:
        stdoutlock.acquire()
        sys.stdout.write("toto")
        sys.stdout.flush()
    finally:
        stdoutlock.release()


    Le plus simple étant d'encapsuler le acquire(), write(), release() dans une fonction.
    • [^] # Re: Il faut protéger les ressources partagées

      Posté par  . Évalué à 4.

      A noter avec le mot clef "with" (depuis Python 2.5) la présence de "contextes" pour les locks, on peut donc remplacer le try..finally par
      """
      with sdtoulock:
      ... sys.stdout.write("toto")
      ... sys.stdout.flush()
      """
    • [^] # Re: Il faut protéger les ressources partagées

      Posté par  . Évalué à 2.

      Je te remercie pour ton aide, mais cela ne résoud pas le problème : les stdout sont remplacés les uns par les autres. Je vais me pencher sur curses plutôt, comme indiqué dans le commentaire ci-dessous. Merci à vous quand même.
  • # curses

    Posté par  . Évalué à 3.

    En utilisant simplement des print dans stdout, ça risque d'être assez velu =)
    Regarde du côté du module curses, qui devrait te permettre de faire ce que tu veux (affichage multilines en console)
    cf http://www.amk.ca/python/howto/curses/
  • # Euh

    Posté par  (site Web personnel) . Évalué à 2.

    Je connais pas mython, mais c'est un bête problème de concurrence et de POO que tu poses là.

    Tu veux pas faire print sur STDOUT.
    Tu veux un objet Out qui gère la sortie.

    Et tu fais
    Out.print(self, self.progression)

    L'objet (unique) Out, tient une table indexée par objets (d'où le passage de self), et qui pointe vers la progression.
    Puis à chaque print, il parcourt la table, et l'affiche

    Out.table.each(obj, prog) {
    Stdout.printf("%s : %i%n",obj.toString, prog);
    }


    Bon, c'est du pseudocode, mais l'idée est là…
    Vu que l'appelle de méthode, lui, est atomique, pas besoin de lock. Et tu peux laisser l'objet Out afficher sans aucun problème sur stdout, avec ncurses, etc.
    • [^] # Re: Euh

      Posté par  . Évalué à 2.

      Merci pour ta réponse, mais je ne comprend pas bien le principe : il faut quand même que j'identifie chaque thread pour pouvoir alimenter la dite table indexée. Est-ce que tu pourrais m'aiguiller vers un lien ? Effectivement c'est un bête problème, mais j'apprends le python aussi pour m'initier à la POO.

      Merci beaucoup en tout cas
      • [^] # Re: Euh

        Posté par  (site Web personnel) . Évalué à 2.

        ta table est indexée par les threads eux même.
        Et si les threads ne sont pas des objets, alors chaque thread contient au moins une variable avec une valeur unique (son nom, etc).

        Tu utilises cet identifiant unique comme index de ta table.

        C'est pas de la POO, c'est de la prog concurrente en fait ça…

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.