Frage

Ich benutze derzeit Generatoren als schnelle Möglichkeit, den Fortschritt langer Prozesse zu erzielen, und ich frage mich, wie es normalerweise getan wird, da ich es nicht sehr elegant finde ...

Lassen Sie mich zuerst erklären, dass ich ein Motor.PY -Modul habe, das eine Videoverarbeitung (Segmentierung, BG/FG -Subtraktion usw.) durchführt, die viel Zeit in Anspruch nimmt (von Sekunden bis zu einigen Minuten).

Ich verwende dieses Modul von einer GUI in WXPython und einem Konsolenskript. Als ich mir angesehen habe, wie Dialoge in WXPython implementiert werden können, sah ich, dass ich irgendwie einen Fortschrittswert erhalten muss, um mein Dialog zu aktualisieren. Dies ist reine Logik, die Sie zugeben ... und habe mich entschlossen, die Anzahl der in meinem verarbeiteten Rahmen zu verwenden Motorfunktionen, geben Sie alle 33 Frames die Stromrahmennummer und geben Sie keine, wenn die Verarbeitung abgeschlossen ist.

Wenn Sie dies tun, sieht es aus, 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()

Das funktioniert sehr gut, es gibt absolut keinen merklichen Geschwindigkeitsverlust, aber ich möchte in der Lage sein, die processMovie () -Funktion aufzurufen, ohne mit Generatoren umgehen zu müssen, wenn ich nicht möchte.

Zum Beispiel mein Konsolenskript, das das Engine -Modul verwendet, kümmert sich nicht um den Fortschritt, ich könnte es verwenden, aber es ist dazu bestimmt, in einer Umgebung ausgeführt zu werden, in der es keine Anzeige gibt, daher kümmere ich mich wirklich nicht um den Fortschritt ...

Jemand mit einem anderen Design, den ich mir ausgedacht habe? (Verwenden von Themen, Globalen, Prozessen usw.)

Es muss irgendwo ein Design geben, das diesen Job sauber macht, denke ich :-)

War es hilfreich?

Lösung

Die Verwendung eines Generators ist dafür in Ordnung, aber der springende Punkt bei der Verwendung von Generatoren ist, sodass Sie die Syntax in der Integration haben:

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

Wenn Sie sich nicht darum kümmern, können Sie entweder sagen:

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

oder entdecken Sie eine Funktion (z. B. Engine.ProcessMovieFull), um dies für Sie zu tun.

Sie können 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 Sie die Datenstücke verarbeiten möchten. Rückrufmodelle ziehen es vor, alle Arbeiten gleichzeitig zu erledigen-das ist der wahre Vorteil von Generatoren.

Andere Tipps

Das klingt nach einem perfekten Fall für Ereignisse. Der Prozess sendet ein "Status -Update -Ereignis", und jeder, der wissen möchte (in diesem Fall das Dialog), hört dieses Ereignis zu.

Wenn Sie einen Generator verwenden, können Sie ihn zunächst auch 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 nicht nachgeben None; Hör auf, nachzugeben, wenn du fertig bist, und verlasse die Funktion. Alternativ erhöhen StopIteration. Dies ist die richtige Art der Beendigung der Erzeugung (und bei Verwendung a for Schleife, es ist notwendig).

Ansonsten mag ich die Idee. Meiner Meinung nach ist dies eine sehr gültige Verwendung von Generatoren.

Vielleicht möchten Sie das machen 33 Konfigurierbar (dh passable auf processMovie als Parameter); 33 scheint eine willkürliche Wahl zu sein, und wenn Sie einen zweistündigen Film verarbeiten, müssen Sie die Fortschrittsleiste nicht alle 33 Bilder aktualisieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top