2009-07-31 8 views
2

ich derzeit Generatoren als eine schnelle Art und Weise bin mit dem Fortschritt der langen Prozesse zu bekommen und ich frage mich, wie es in der Regel getan, wie ich es nicht sehr elegant finden ...Nutzung von Generatoren als Progression Notifier

Lassen Sie mich zuerst erklären, ich habe ein Modul Engine.py, die einige Videoverarbeitung (Segmentierung, bg/fg Subtraktion, usw.), die viel Zeit (von Sekunden bis zu einigen Minuten) dauert.

Ich verwende dieses Modul von einer GUI in WXPYTHON und einem Konsolenskript geschrieben. Als ich sah, wie man Fortschrittdialoge in wxpython implementiert, sah ich, dass ich irgendwie einen Fortschrittswert bekommen muss, um meinen Dialog zu aktualisieren, was pure Logik ist ... Also entschied ich mich, die Anzahl der verarbeiteten Frames zu verwenden In meinen Motorfunktionen, erhalte alle 33 Frames die aktuelle Frame-Nummer und gib keine aus, wenn die Verarbeitung abgeschlossen ist.

durch das hier zu tun ist, wie es aussieht:

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() 

die sehr gut funktioniert, gibt es absolut keine spürbaren Geschwindigkeitsverlust, aber ich möchte in der Lage sein processMovie() Funktion aufrufen, ohne beschäftigen zu mit Generatoren, wenn ich nicht will.

Zum Beispiel mein Konsole Skript, das das Modul verwendet, kümmert sich nicht um den Fortschritt, ich könnte es verwenden, aber es ist bestimmt, in einer Umgebung ausgeführt zu werden, in der es keine Anzeige gibt, also interessiert mich wirklich nicht Fortschritt ...

Wer mit einem anderen Design, das ich kam? (Unter Verwendung von Fäden, Globals, Prozesse, etc.)

Es muss ein Design irgendwo sein, dass sich dieser Job Cleany Ich denke :-)

Antwort

2

Mit einem Generator für diese in Ordnung ist, aber der ganze Punkt Generatoren der Verwendung ist so können Sie gebautet Syntax:

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

Wenn Sie nicht über das kümmern, dann können Sie entweder sagen:

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

oder eine Funktion aussetzen (zB engine.processMovieFull.) zu tun Dies für dich.

Sie könnten auch einen einfachen Rückruf verwenden:

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

... aber das ist nicht so schön, wenn man Stück für Stück die Daten verarbeitet werden sollen; Callback-Modelle bevorzugen alle Arbeiten auf einmal - das ist der wahre Vorteil von Generatoren.

+0

Gott ich liebe die eingebaute Syntax !! wusste es nicht, macht es so viel sauberer für meine Augen :-) Danke !! – attwad

0

Vor allem, wenn Sie einen Generator verwenden, könnte man genauso gut es als Iterator verwenden:

state = self.engine.processMovie() 

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

dlg.Destroy() 

und ergeben keine None; hören Sie auf nachzugeben, wenn Sie fertig sind und verlassen Sie die Funktion; alternativ raise StopIteration. Dies ist die korrekte Art, die Generierung zu beenden (und wenn Sie eine for-Schleife verwenden, ist dies erforderlich).

Ansonsten mag ich die Idee. Meiner Meinung nach ist dies ein sehr gültiger Einsatz von Generatoren.

Sie möchten vielleicht die 33 konfigurierbar machen (d. H.passierbar zu processMovie als Parameter); 33 scheint wie eine willkürliche Wahl, und wenn Sie einen zweistündigen Film bearbeiten, müssen Sie den Fortschrittsbalken nicht alle 33 Frames aktualisieren, denke ich.

+0

Ja natürlich ist die 33 konfigurierbar, es kommt auf die Länge des Films an. Danke für den Tipp über StopIteration, wusste nichts davon. – attwad

+0

Es ist besser, die Ausbeute zu verwenden, um einen Generator für Sie zu erstellen, als die Generator-API selbst zu implementieren. Es ist viel sauberer für die meisten Aufgaben. –

+0

Sie müssen StopIteration nicht wirklich erhöhen. Wenn die (erzeugende) Funktion stoppt, d.h. Sie etwas zurückgeben oder das Ende der Funktion erreichen, wird auch die Iteration gestoppt. – balpha

1

Das klingt wie ein perfekter Fall für Ereignisse. Der Prozess sendet ein "Status-Update-Ereignis" und jeder, der es wissen möchte (in diesem Fall den Dialog), hört auf dieses Ereignis.

+0

das bindet mich an wxpython Ereignisse, aber meine Konsolenanwendung muss unabhängig sein. – attwad

+0

Nein, tut es nicht. Nichts zwingt Sie, wxpythons-Ereignisse zu verwenden. Sie brauchen nur irgendwelche Ereignisse. Hier ist ein Beispiel für ein Ereignissystem. Sie können das verwenden oder den Code in Ihren eigenen kopieren. http://svn.zope.org/zope.event/trunk/src/zope/event/__init__.py?rev=75122&view=markup –