Ich möchte auf eine warten Aufgabe <T> mit einigen speziellen Regeln abgeschlossen ist: Wenn sie nach X Millisekunden nicht abgeschlossen wurde, möchte ich dem Benutzer eine Nachricht anzeigen. Und wenn es nach Y Millisekunden nicht abgeschlossen ist, möchte ich automatisch eine Stornierung beantragen .
Ich kann Task.ContinueWith verwenden, um asynchron auf den Abschluss der Aufgabe zu warten (dh eine Aktion zu planen, die ausgeführt werden soll, wenn die Aufgabe abgeschlossen ist), aber dies erlaubt keine Angabe eines Zeitlimits. Ich kann Task.Wait verwenden, um synchron zu warten, bis die Aufgabe mit einem Timeout abgeschlossen ist, aber das blockiert meinen Thread. Wie kann ich asynchron warten, bis die Aufgabe mit einer Zeitüberschreitung abgeschlossen ist?
CancellationTokenSource
. Dem Konstruktor stehen zwei Überladungen zur Verfügung, eine mit einer Verzögerung von ganzzahligen Millisekunden und eine mit einer TimeSpan-Verzögerung.Antworten:
Wie wäre es damit:
Und hier ist ein großartiger Blog-Beitrag "Crafting a Task.TimeoutAfter Method" (vom MS Parallel Library-Team) mit weiteren Informationen zu solchen Dingen .
Ergänzung : Auf Anfrage eines Kommentars zu meiner Antwort finden Sie hier eine erweiterte Lösung, die die Bearbeitung von Stornierungen umfasst. Beachten Sie, dass das Übergeben der Stornierung an die Aufgabe und den Timer bedeutet, dass es mehrere Möglichkeiten gibt, die Stornierung in Ihrem Code zu erfahren. Sie sollten sicher sein, dass Sie alle Stornierungen testen und sicher sein, dass Sie alle ordnungsgemäß verarbeiten. Überlassen Sie nicht dem Zufall verschiedene Kombinationen und hoffen Sie, dass Ihr Computer zur Laufzeit das Richtige tut.
quelle
Task.Delay
Aufgabe von einem Systemzeitgeber unterstützt wird, der weiterhin verfolgt wird, bis das Zeitlimit abläuft, unabhängig davon, wie lange esSomeOperationAsync
dauert. Wenn dieses gesamte Code-Snippet häufig in einer engen Schleife ausgeführt wird, verbrauchen Sie Systemressourcen für Timer, bis alle Zeitüberschreitungen auftreten. Die Möglichkeit, dies zu beheben, besteht darin, eine zu übergebenCancellationToken
, die Sie nach Abschluss der Freigabe der Timer-RessourceTask.Delay(timeout, cancellationToken)
abbrechenSomeOperationAsync
.Task
, wird jede von der Task gespeicherte Ausnahme an diesem Punkt erneut ausgelöst. Dies gibt Ihnen die Möglichkeit,OperationCanceledException
(wenn abgebrochen) oder eine andere Ausnahme (falls fehlerhaft) zu fangen .Task.Wait(timeout)
würde synchron blockieren statt asynchron warten.Hier ist eine Version der Erweiterungsmethode, die das Abbrechen des Zeitlimits beinhaltet, wenn die ursprüngliche Aufgabe abgeschlossen ist, wie von Andrew Arnott in einem Kommentar zu seiner Antwort vorgeschlagen .
quelle
using
Block seintask.Result
wenn es zweimal ausgeführt wird.task
) im Falle einer Zeitüberschreitung weiterhin ausgeführt?TimeoutException
hat eine geeignete Standardmeldung. Überschreiben mit "Die Operation ist abgelaufen." fügt keinen Wert hinzu und verursacht tatsächlich einige Verwirrung, indem impliziert wird, dass es einen Grund gibt, ihn zu überschreiben.Sie können
Task.WaitAny
damit die erste von mehreren Aufgaben abwarten.Sie können zwei zusätzliche Aufgaben erstellen (die nach den angegebenen Zeitüberschreitungen abgeschlossen werden) und dann
WaitAny
warten, bis die Aufgaben abgeschlossen sind. Wenn die zuerst erledigte Aufgabe Ihre "Arbeits" -Aufgabe ist, sind Sie fertig. Wenn es sich bei der zuerst abgeschlossenen Aufgabe um eine Zeitüberschreitungsaufgabe handelt, können Sie auf die Zeitüberschreitung reagieren (z. B. Stornierung der Anforderung).quelle
below
.... was ist das? basierend auf SO Bestellung?Was ist mit so etwas?
Sie können die Option Task.Wait verwenden, ohne den Hauptthread mit einer anderen Task zu blockieren.
quelle
Hier ist ein vollständig ausgearbeitetes Beispiel, das auf der am besten bewerteten Antwort basiert:
Der Hauptvorteil der Implementierung in dieser Antwort besteht darin, dass Generika hinzugefügt wurden, sodass die Funktion (oder Aufgabe) einen Wert zurückgeben kann. Dies bedeutet, dass jede vorhandene Funktion in eine Timeout-Funktion eingeschlossen werden kann, z.
Vor:
Nach:
Dieser Code erfordert .NET 4.5.
Vorsichtsmaßnahmen
Nachdem Sie diese Antwort gegeben haben, ist es im Allgemeinen keine gute Praxis, während des normalen Betriebs Ausnahmen in Ihren Code zu werfen, es sei denn, Sie müssen unbedingt:
Verwenden Sie diesen Code nur, wenn Sie die aufgerufene Funktion absolut nicht ändern können, sodass nach einer bestimmten Zeit eine Zeitüberschreitung auftritt
TimeSpan
.Diese Antwort gilt nur für Bibliotheksbibliotheken von Drittanbietern, die Sie einfach nicht umgestalten können, um einen Timeout-Parameter einzuschließen.
Wie schreibe ich robusten Code
Wenn Sie robusten Code schreiben möchten, lautet die allgemeine Regel:
Wenn Sie dies nicht tun diese Regel einhalten, wird Ihr Code möglicherweise einen Vorgang ausführen, der aus irgendeinem Grund fehlschlägt. Dann wird er auf unbestimmte Zeit blockiert und Ihre App ist gerade dauerhaft hängen geblieben.
Wenn nach einiger Zeit eine angemessene Zeitüberschreitung auftritt, bleibt Ihre App extrem lange hängen (z. B. 30 Sekunden). Dann wird entweder ein Fehler angezeigt und der fröhliche Weg fortgesetzt oder es wird erneut versucht.
quelle
Mit Stephen Clearys ausgezeichneter AsyncEx- Bibliothek können Sie Folgendes tun:
TaskCanceledException
wird im Falle einer Zeitüberschreitung ausgelöst.quelle
Dies ist eine leicht verbesserte Version früherer Antworten.
CancellationToken
die ursprüngliche Aufgabe bereitstellen , und wenn eine Zeitüberschreitung auftritt, erhalten SieTimeoutException
stattdessenOperationCanceledException
.Verwendungszweck
InnerCallAsync
Die Fertigstellung kann lange dauern.CallAsync
schließt es mit einer Zeitüberschreitung ab.quelle
timeoutCancellation
indelayTask
. Derzeit, wenn Sie Stornierung feuern,CancelAfterAsync
kann werfenTimeoutException
statt anstattTaskCanceledException
, UrsachedelayTask
kann zuerst beendet werden.WhenAny
demselben Token abgebrochen werdenWhenAny
. Diese Annahme war falsch. Ich habe die Antwort bearbeitet. Vielen Dank!Verwenden Sie einen Timer , um die Nachricht und die automatische Stornierung zu verarbeiten. Wenn die Aufgabe abgeschlossen ist, rufen Sie Dispose für die Timer auf, damit sie niemals ausgelöst werden. Hier ist ein Beispiel; Ändern Sie taskDelay in 500, 1500 oder 2500, um die verschiedenen Fälle anzuzeigen:
Außerdem bietet Async CTP eine TaskEx.Delay-Methode, mit der die Timer in Aufgaben für Sie eingeschlossen werden. Dies kann Ihnen mehr Kontrolle geben, um beispielsweise den TaskScheduler für die Fortsetzung festzulegen, wenn der Timer ausgelöst wird.
quelle
task.Wait()
.Eine andere Möglichkeit, dieses Problem zu lösen, ist die Verwendung von Reactive Extensions:
Testen Sie oben mit dem folgenden Code in Ihrem Unit-Test, es funktioniert für mich
Möglicherweise benötigen Sie den folgenden Namespace:
quelle
Eine generische Version der obigen Antwort von @ Kevan unter Verwendung von Reactive Extensions.
Mit optionalem Scheduler:
Übrigens: Wenn ein Timeout auftritt, wird eine Timeout-Ausnahme ausgelöst
quelle
Wenn Sie die Aufgabe mit einer BlockingCollection planen, kann der Produzent die möglicherweise lange laufende Aufgabe ausführen, und der Verbraucher kann die TryTake-Methode verwenden, in die ein Timeout- und Abbruchtoken integriert ist.
quelle
Ich fühlte die
Task.Delay()
Aufgabe undCancellationTokenSource
in den anderen Antworten ein bisschen viel für meinen Anwendungsfall in einer engen Netzwerkschleife.Und obwohl Joe Hoags Crafting a Task.TimeoutAfter-Methode in MSDN-Blogs inspirierend war, war ich es ein wenig leid, sie zu verwenden
TimeoutException
aus dem gleichen Grund wie oben für die Flusskontrolle zu verwenden, da Timeouts häufiger erwartet werden als nicht.Also habe ich mich dafür entschieden, das auch die im Blog erwähnten Optimierungen behandelt:
Ein Beispiel für einen Anwendungsfall ist folgender:
quelle
Einige Varianten von Andrew Arnotts Antwort:
Wenn Sie auf eine vorhandene Aufgabe warten und herausfinden möchten, ob sie abgeschlossen oder abgelaufen ist, sie jedoch nicht abbrechen möchten, wenn das Zeitlimit auftritt:
Wenn Sie eine Arbeitsaufgabe starten und die Arbeit abbrechen möchten, wenn das Zeitlimit auftritt:
Wenn Sie bereits eine Aufgabe erstellt haben, die Sie abbrechen möchten, wenn eine Zeitüberschreitung auftritt:
Ein weiterer Kommentar: Diese Versionen brechen den Timer ab, wenn das Timeout nicht auftritt, sodass sich bei mehreren Anrufen keine Timer häufen.
sjb
quelle
Ich fasse die Ideen einiger anderer Antworten hier und diese Antwort in einem anderen Thread zu einer Erweiterungsmethode im Try-Stil zusammen. Dies hat einen Vorteil, wenn Sie eine Erweiterungsmethode wünschen und dennoch eine Ausnahme bei Zeitüberschreitung vermeiden möchten.
quelle
Tun Sie dies auf keinen Fall, aber es ist eine Option, wenn ... mir kein gültiger Grund einfällt.
quelle