Ich kenne PipeTo
, aber einige Sachen, wie synchrones Warten auf verschachtelte Fortsetzung, scheint gegen die Async & Amp; Warte.
Also, meine erste Frage [1] wäre: Gibt es hier irgendeine "Magie", so dass wir synchron auf verschachtelte Aufgaben in einer Fortsetzung warten können und sie am Ende immer noch asynchron ist?
Während wir bei async & amp; Unterschiede erwarten, wie werden Fehler behandelt?
Lassen Sie uns ein einfaches Beispiel erstellen:
%Vor%In einer 'normalen', asynchronen & amp; Warte so:
%Vor%Die Ausnahme wird wie erwartet von der ersten Operation in die Luft gehen.
Lassen Sie uns nun einen Akteur erstellen, der mit diesen asynchronen Operationen arbeiten wird. Für ein Argument sagen wir, dass CalculateAnswerAsync
und ConvertAsync
nacheinander als eine vollständige Operation verwendet werden sollten (ähnlich wie zum Beispiel StreamWriter.WriteLineAsync
und StreamWriter.FlushAsync
, wenn Sie nur eine Zeile schreiben wollen) zu einem Stream).
Wenn es keine Ausnahmen gibt, bekomme ich immer noch Got 42 :)
ohne irgendwelche Probleme, was mich zum 'magischen' Punkt über [1] bringt.
Sind auch die in einem Beispiel optionalen Flags AttachedToParent
und ExecuteSynchronously
oder sind sie so gut wie erforderlich, damit alles wie gewünscht funktioniert? Sie scheinen keine Auswirkungen auf die Ausnahmebehandlung zu haben ...
Wenn nun CalculateAnswerAsync
eine Exception auslöst, was bedeutet, dass result.Result
throws AggregateException
, dann wird es spurlos verschluckt.
Was soll ich hier tun, wenn es sogar möglich ist, die Ausnahme innerhalb eines asynchronen Vorgangs zum Absturz des Aktors als 'normale' Ausnahme zu machen?
Die Freuden der Fehlerbehandlung in der TPL :)
Task
innerhalb eines Actors starten, wird diese Task unabhängig von Ihrem Actor für ThreadPool
ausgeführt. Das bedeutet, dass alles, was Sie innerhalb dieses Task
tun, bereits von Ihrem Akteur asynchron ist - weil es auf einem anderen Thread läuft. Diese ist der Grund, warum ich ein% co_de gemacht habe % rufe das Task.Wait
Beispiel auf, mit dem du oben verlinkt hast. Macht keinen Unterschied für den Schauspieler - es sieht nur aus wie eine langwierige Aufgabe. PipeTo
die während der Ausführung erfasste Ausnahme auslösen. Daher sollten Sie in conversionTask.Result
eine Fehlerbehandlung hinzufügen, um sicherzustellen, dass Ihr Akteur benachrichtigt wird ging schief. Beachten Sie, dass ich genau das hier getan habe: Ссылка - Wenn du deine Exceptions in Botschaften verwandelst, mit denen dein Schauspieler umgehen kann: Vögel fangen an zu singen, Regenbögen scheinen, und TPL-Fehler hören auf, eine Quelle von Schmerz und Qual zu sein. Nun, wenn CalculateAnswerAsync eine Ausnahme auslöst, was bedeutet result.Result löst AggregateException aus, es ist ziemlich verschluckt ohne eine Spur.
Das Task
enthält die Liste innerer Ausnahmen, die darin enthalten sind - der Grund, warum die TPL dieses Konzept von Aggregatfehlern hat, ist (a) wenn Sie eine Aufgabe haben, die die Fortsetzung mehrerer Aufgaben aggregiert ist , dh AggregateException
oder (b) Sie haben Fehler, die die Task.WhenAll
-Kette bis zum Elternteil weitergegeben haben. Sie können auch den Aufruf ContinueWith
aufrufen, um geschachtelte Ausnahmen leichter zu verwalten.
Der Umgang mit Ausnahmen von der TPL ist ein Ärgernis, das ist richtig - aber der beste Weg, damit umzugehen, ist AggregateException.Flatten()
exceptions in try..catch..
und wandelt sie in Nachrichtenklassen um, mit denen Ihr Akteur umgehen kann.
Sind die AttachedToParent- und ExecuteSynchronicous-Flags, die in einem Beispiel angegeben sind, optional, oder sind sie so gut wie erforderlich, damit alles wie gewünscht funktioniert?
Dies ist hauptsächlich ein Problem, wenn Sie Fortsetzungen auf Fortsetzungen haben - Task
verwendet diese Flags automatisch für sich. Es hat keinen Einfluss auf die Fehlerbehandlung, stellt jedoch sicher, dass Ihre Fortsetzungen sofort im selben Thread ausgeführt werden wie das ursprüngliche PipeTo
.
Ich empfehle, diese Flags nur zu verwenden, wenn Sie viele verschachtelte Fortsetzungen machen - die TPL beginnt, einige Freiheiten zu nehmen, wie sie Ihre Tasks plant, wenn Sie tiefer als 1 Fortsetzung gehen (und Flags wie OnlyOnCompleted nicht mehr sind) akzeptiert nach mehr als 1 Fortsetzung.)
Nur um hinzuzufügen, was Aaron gesagt hat. Seit gestern unterstützen wir sichere Async erwarten Akteure innerhalb der Task-Dispatcher.
%Vor% Dies ist nicht unser Standard-Dispatcher, da er einen Preis für Leistung / Durchsatz hat.
Es besteht auch die Gefahr von Deadlocks, wenn Sie Tasks auslösen, die blockieren (z. B. task.Wait()
oder task.Result
verwenden).
Daher ist das PipeTo
-Muster immer noch der bevorzugte Ansatz, da es dem Actor-Modell mehr entspricht.
Aber die asynchrone Unterstützung ist für Sie als zusätzliches Werkzeug da, wenn Sie wirklich eine TPL-Integration machen müssen.
Diese Funktion verwendet PipeTo
unter den Covern.
Es wird jede Taskfortsetzung übernehmen und diese in einer speziellen Nachricht einschließen und diese Nachricht an den Aktor zurückgeben und diese Aufgabe innerhalb des akteurseigenen Parallelkontexts ausführen.