Manchmal startet der Benutzer einen erweiterten technischen Vorgang, dessen Ausführung eine Weile dauert. In diesen Fällen ist es normalerweise hilfreich, eine Art Fortschrittsbalken zusammen mit Informationen darüber anzuzeigen, welche Aufgabe gerade ausgeführt wird.
Um eine enge Kopplung der Benutzeroberfläche und der Logikschichten zu vermeiden, ist es normalerweise am besten, die Kommunikation über eine Art Proxy durchzuführen. Das heißt, das Back-End sollte nicht seine eigenen UI-Elemente manipulieren oder sogar direkt mit der Zwischenschicht interagieren.
Offensichtlich muss es irgendwo einen Rückruf geben, damit dies funktioniert. Ich habe es im Allgemeinen auf zwei Arten implementiert:
Übergeben Sie ein veränderbares Objekt an das Back-End, und lassen Sie das Back-End im Verlauf Änderungen daran vornehmen. Das Objekt benachrichtigt das Front-End, wenn eine Änderung auftritt.
Übergeben Sie eine Rückruffunktion des Formulars
void f(ProgressObject)
oderProgressObject -> unit
des vom Backend aufgerufenen Formulars . In diesem Fall erstellt das Back-End dasProgressObject
und es ist vollständig passiv. Ich nehme an, es muss jedes Mal ein neues Objekt erstellen, wenn es den Fortschritt melden möchte.
Was sind die Nachteile und Vorteile dieser Methoden? Gibt es eine vereinbarte beste Methode? Gibt es unterschiedliche Umstände für ihre Verwendung?
Gibt es völlig andere Techniken zur Berichterstattung über Fortschritte, die ich übersehen habe?
quelle
BackgroundWorker
diese RH-Erwähnungen. Eingewickelt in eine benutzerdefinierte Klasse zusammen mit einem "Fortschrittsformular" usw. und einem einfachen Mechanismus zum Kommunizieren einer Ausnahme - wieBackgroundWorker
beabsichtigt in einem separaten Thread ausgeführt. In dem Maße, in dem wir seine Funktionen auf eine von .Net vorgeschlagene Weise verwenden, könnte man sagen, dass dies idiomatisch ist. Und in jedem gegebenen Sprach- / Rahmenkontext kann "idiomatisch" am besten sein.Antworten:
Es ist schwierig, die Effizienz auszugleichen, wenn das Backend diesbezüglich benachrichtigt. Ohne Sorgfalt können Sie feststellen, dass das Erhöhen Ihres Fortschritts die Zeit, die zum Abschließen des Vorgangs benötigt wird, verdoppelt oder verdreifacht, wenn Sie eine sehr reibungslose Fortschrittsaktualisierung anstreben.
Ich verstehe den Unterschied hier nicht so sehr.
Abfrage vom Frontend in einem separaten Thread mit atomaren Inkrementen im Backend. Abfragen sind hier sinnvoll, da es sich um eine Operation handelt, die in einem begrenzten Zeitraum abgeschlossen wird und die Wahrscheinlichkeit, dass das Frontend Statusänderungen erfasst, hoch ist, insbesondere wenn Sie einen seidenweichen Fortschrittsbalken anstreben. Sie können Bedingungsvariablen in Betracht ziehen, wenn Sie die Idee des Abrufs vom Frontend-Thread nicht mögen. In diesem Fall möchten Sie jedoch möglicherweise vermeiden, bei jedem einzelnen granularen Fortschrittsbalkeninkrement eine Benachrichtigung zu erhalten.
quelle
Dies ist der Unterschied zwischen einem Push- und Pull- Benachrichtigungsmechanismus.
Das veränderbare Objekt (das Pull ) muss von der Benutzeroberfläche wiederholt abgefragt und synchronisiert werden, wenn Sie erwarten, dass die Back-End-Aufgabe in einem Hintergrund- / Worker-Thread ausgeführt wird.
Der Rückruf (der Push ) schafft nur dann Arbeit für die Benutzeroberfläche, wenn sich tatsächlich etwas ändert. Viele UI-Frameworks verfügen auch über einen invokeOnUIThread, der von einem Worker-Thread aufgerufen werden kann, damit ein Teil des Codes auf dem UI-Thread ausgeführt wird, sodass Sie die Änderungen tatsächlich vornehmen können, ohne auf threadbezogene Gefahren einzugehen. (Wortspiel beabsichtigt)
Im Allgemeinen sind Push- Benachrichtigungen vorzuziehen, da sie nur dann funktionieren, wenn Arbeit erledigt werden muss.
quelle
The mutable object (the pull) will need to be repeatably polled by the UI and synchronized if you expect the back-end task to be executed in a background/worker thread.
- Nicht, wenn das veränderbare Objekt der Dialog selbst oder eine Arbeitsschnittstelle dazu ist. Das ist natürlich sowieso ein Rückruf.Ich verwende Websockets mit AngularJS. Wenn das Front-End eine Nachricht empfängt, wird sie in einem bestimmten Nachrichtenbereich angezeigt, der nach einigen Sekunden leer wird. Am Backend poste ich einfach Statusnachrichten in einer Nachrichtenwarteschlange. Ich sende nur Text, aber es gibt keinen Grund, warum ich kein Statusobjekt mit Werten wie Prozentsatz abgeschlossen oder Übertragungsgeschwindigkeit senden konnte.
quelle
Sie erwähnen Ihre "zwei Wege", als wären sie getrennte Konzepte, aber ich möchte darauf ein wenig zurückkommen.
Sie haben bereits gesagt, dass Sie eine enge Kopplung der Benutzeroberfläche und der Logik vermeiden möchten, sodass ich davon ausgehen kann, dass dieses "veränderbare Objekt", das Sie übergeben, tatsächlich eine Implementierung einer bestimmten Schnittstelle ist, die im Logikmodul definiert ist. Als solches ist dies lediglich eine andere Möglichkeit, einen Rückruf an den Prozess weiterzuleiten, der regelmäßig mit Informationen über den Fortschritt aufgerufen wird.
Vor- und Nachteile ...
Ein Nachteil für Methode (1) ist, dass die Klasse, die die Schnittstelle implementiert, dies nur einmal tun kann. (Wenn Sie verschiedene Jobs mit unterschiedlichen Aufrufen ausführen möchten, benötigen Sie eine switch-Anweisung oder das Besuchermuster.) Mit Methode (2) kann dasselbe Objekt für jeden Aufruf des Backend-Codes einen anderen Rückruf verwenden, ohne dass ein erforderlich ist Schalter.
Eine Stärke von Methode (1) besteht darin, dass es viel einfacher ist, mehrere Methoden auf der Schnittstelle zu haben, als die mehrfachen Rückrufe von Methode (2) oder einen einzelnen Rückruf mit einer switch-Anweisung für mehrere Kontexte zu behandeln.
quelle
Die Techniken, die Sie verwenden können, können sehr unterschiedlich sein.
Ich versuche es mit einem anderen Szenario herauszufinden
Eine einfache Anmeldeanforderung an db (mittlere Antwort von db mit einem Element) benötigt keinen Berichtsfortschritt, kann jedoch immer den UI-Thread in einer separaten Task abfeuern. Async oder Backgroundworker, hier benötigen Sie nur einen Rückruf für das Ergebnis.
Aber was ist, wenn Sie nach Ihrem gesamten Inventar mit 1 Mio. Artikel fragen? Diese Abfrage sollte einige Minuten dauern. In diesem Fall müssen Sie Ihren Perport-Fortschritt in Ihrer Geschäftslogik in Formularelementen implementieren. Anschließend können Sie Ihre Benutzeroberfläche aktualisieren und erhalten möglicherweise die Option Rückruf abbrechen.
Gleicher Fall für den Dateidownload. Sie können Ihren Fortschrittsrückruf hier jederzeit in Form von Bytes implementieren und die gesamte Kommunikationskontrolle über http als Muster beibehalten.
Bei meinem persönlichen Ansatz implementiere ich meine Geschäftsfortschrittslogik nur für meine Kunden, ohne andere Objekte mit dem Endpunkt zu teilen.
quelle