2009-07-31 3 views
2

Je suis en train d'utiliser des générateurs comme un moyen rapide pour obtenir les progrès des processus longs et je me demande comment est-il fait habituellement que je trouve pas très élégant ...utilisation des générateurs comme un notificateur de progression

Laissez-moi vous expliquer d'abord, j'ai un module engine.py qui fait un peu de traitement vidéo (segmentation, soustraction bg/fg, etc.) qui prend beaucoup de temps (de quelques secondes à plusieurs minutes). J'utilise ce module à partir d'une interface graphique écrite en wxpython et d'un script de console. Quand j'ai regardé comment implémenter des dialogues de progression dans wxpython, j'ai vu que je devais obtenir une valeur de progression pour mettre à jour mon dialogue, ce qui est de la pure logique ... J'ai donc décidé d'utiliser le nombre de frames traités dans mes fonctions de moteur, donnez le nombre d'images en cours toutes les 33 images et cédez None lorsque le traitement est terminé.

en faisant cela, voici à quoi il ressemble:

dlg = wx.ProgressDialog("Movie processing", "Movie is being written...", 
          maximum = self.engine.endProcessingFrame,self.engine.startProcessingFrame, 
          parent=self, 
          style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_SMOOTH | wx.PD_CAN_ABORT) 
state = self.engine.processMovie() 
f = state.next() 
while f != None: 
    c, s = dlg.Update(f, "Processing frame %d"%f) 
    if not c:break 
    f = state.next() 
dlg.Destroy() 

Cela fonctionne très bien, il n'y a absolument aucune perte de vitesse notable, mais je voudrais être en mesure d'appeler la fonction processMovie() sans avoir à traiter avec des générateurs si je ne veux pas. Par exemple, mon script de console qui utilise le module moteur ne se soucie pas de la progression, je pourrais l'utiliser mais il est destiné à être exécuté dans un environnement où il n'y a pas d'affichage, donc je ne me soucie vraiment pas de la progrès ...

Quelqu'un avec un autre design que celui que j'ai inventé? (En utilisant les fils, les processus, GLOBALS etc.)

Il doit y avoir quelque part une conception qui fait cela CLEANY de travail, je pense :-)

Répondre

2

L'utilisation d'un générateur est très bien pour cela, mais le point de l'ensemble de l'utilisation des générateurs est de sorte que vous pouvez builtin syntaxe:

for f in self.engine.processMovie(): 
    c, s = dlg.Update(f, "Processing frame %d"%f) 
    if not c: break 

Si vous ne se soucient pas de cela, alors vous pouvez dire:

for f in self.engine.processMovie(): pass 

ou exposer une fonction (par exemple engine.processMovieFull.) faire c'est pour vous.

Vous pouvez également utiliser un rappel simple:

def update_state(f): 
    c, s = dlg.Update(f, "Processing frame %d"%f) 
    return c 
self.engine.processMovie(progress=update_state) 

... mais ce n'est pas aussi bien si vous voulez traiter les données fragmentaires; Les modèles de rappel préfèrent faire tout le travail en même temps - c'est le véritable avantage des générateurs.

+0

Dieu J'aime la syntaxe intégrée !! Je ne savais pas à ce sujet, le rend tellement plus propre à mes yeux :-) merci !! – attwad

0

Tout d'abord, si vous utilisez un générateur, vous pourriez aussi bien l'utiliser comme un itérateur:

state = self.engine.processMovie() 

for f in state: 
    c, s = dlg.Update(f, "Processing frame %d"%f) 
    if not c: 
     break 

dlg.Destroy() 

Et ne donnent pas None; arrêtez de céder lorsque vous avez terminé et quittez la fonction; alternativement augmenter StopIteration. C'est la manière correcte de mettre fin à la génération (et lorsque vous utilisez une boucle for, c'est nécessaire).

À part ça, j'aime l'idée. À mon avis, c'est une utilisation très valable des générateurs.

Vous pouvez configurer le paramètre 33 (c.-à-d.passable à processMovie en tant que paramètre); 33 semble être un choix arbitraire, et si vous traitez un film de deux heures, il n'y a pas besoin de mettre à jour la barre de progression toutes les 33 images je suppose.

+0

Oui bien sûr, le 33 est configurable, cela dépend de la longueur du film. Merci pour le conseil sur StopIteration, je ne savais pas à ce sujet. – attwad

+0

Il vaut mieux utiliser le rendement pour créer un générateur pour vous que d'implémenter vous-même l'API du générateur. C'est beaucoup plus propre pour la plupart des tâches. –

+0

Vous n'avez pas vraiment besoin d'augmenter StopIteration. Si la fonction (génératrice) s'arrête, c'est-à-dire que vous retournez quelque chose ou atteignez la fin de la fonction, l'itération est également arrêtée. – balpha

1

Cela ressemble à un cas parfait pour les événements. Le processus envoie un "événement de mise à jour d'état", et toute personne qui veut savoir (dans ce cas la boîte de dialogue) écoute cet événement.

+0

qui me lie aux événements wxpython, mais mon application console doit être indépendante. – attwad

+0

Non, ce n'est pas le cas. Rien ne vous oblige à utiliser les événements wxpythons. Vous avez juste besoin d'événements de quelque sorte. Voici un exemple d'un système d'événements. Vous pouvez l'utiliser ou copier le code dans le vôtre. http://svn.zope.org/zope.event/trunk/src/zope/event/__init__.py?rev=75122&view=markup –

Questions connexes