Alle, hier ist eine Frage über Design/Best Practices für einen komplexen Fall der Stornierung Aufgabe: s in C#. Wie implementieren Sie die Löschung einer gemeinsamen Aufgabe?So implementieren Sie die Aufhebung der gemeinsamen Aufgabe: s in C#
Nehmen wir als minimales Beispiel Folgendes an: wir haben eine lang laufende, kooperativ kündbare Operation 'Arbeit'. Es akzeptiert ein Abbruch-Token als Argument und löst aus, wenn es abgebrochen wurde. Es arbeitet mit einem bestimmten Anwendungszustand und gibt einen Wert zurück. Ihr Ergebnis wird von zwei UI-Komponenten unabhängig benötigt.
Während die Anwendung Zustand ist unverändert, sollte der Wert der Arbeitsfunktion zwischengespeichert wird, und wenn eine Berechnung nicht abgeschlossen ist, sollte eine neue Anforderung nicht eine zweite Berechnung starten, sondern startet auf ein Ergebnis warten.
Eine der UI-Komponenten sollte in der Lage sein, ihre Aufgabe abzubrechen, ohne dass sich dies auf die anderen Aufgaben der UI-Komponenten auswirkt.
Sind Sie bei mir so weit?
Das Obige kann durch die Einführung eines Task-Cache erreicht werden, die die eigentliche Arbeit Aufgabe in TaskCompletionSources Wraps, deren Aufgabe: s werden dann an die UI-Komponenten zurückgeführt. Wenn eine UI-Komponente ihre Aufgabe abbricht, wird nur die TaskCompletionSource-Aufgabe und nicht die zugrunde liegende Aufgabe aufgegeben. Das ist alles gut. Die UI-Komponenten erstellen die Annullierungsquelle, und die Anforderung zum Abbrechen ist ein normales Top-down-Design, wobei die kooperierende TaskCompletionSource-Aufgabe unten angezeigt wird.
Nun zu dem wirklichen Problem. Was tun, wenn sich der Anwendungsstatus ändert? Nehmen wir an, dass es nicht machbar ist, wenn die Funktion 'Arbeit' auf einer Kopie des Zustands ausgeführt wird.
Eine Lösung wäre, um die Zustandsänderung in der Task-Cache (oder dort etwa) zu hören. Wenn der Cache über ein CancellationToken verfügt, das von der zugrunde liegenden Task verwendet wird, die die Work-Funktion ausführt, kann sie abgebrochen werden. Dies könnte dann eine Annullierung aller angefügten TaskCompletionSources-Tasks auslösen, und somit würden beide UI-Komponenten abgebrochene Tasks erhalten. Dies ist eine Art Bottom-Up-Stornierung.
Gibt es einen bevorzugten Weg, dies zu tun? Gibt es ein Designmuster, das es irgendwo beschreibt?
Die Bottom-Up-Stornierung kann implementiert werden, aber es fühlt sich ein bisschen komisch an. Die UI-Task wird mit einem CancellationToken erstellt, aber aufgrund eines anderen (inneren) CancellationTokens abgebrochen. Auch, da die Token nicht gleich sind, kann die OperationCancelledException nicht nur in der Benutzeroberfläche ignoriert werden - das würde (schließlich) führen zu einer Ausnahme in der äußeren Aufgabe geworfen werden: s Finalizerthread.
Ausgezeichnete Frage, obwohl meine erste Reaktion war "tl; dr" – dtb
Also, zu klären; Sie haben zwei Consumer des Task-Ergebnisses, und Sie möchten nur eine Task den Wert pro Anwendungsstatus berechnen; Sie möchten dennoch, dass jeder Verbraucher "abbrechen" kann, indem er auf das Ergebnis der Aufgabe wartet? – Tejs
ja, aber auch, dass eine Änderung des Zustands die Berechnung abbrechen sollte. – 4ZM