Async-API-Aufruf innerhalb eines Actors und Ausnahmen

8

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).

%Vor%

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?

    
Patryk Ćwiek 16.02.2015, 21:02
quelle

2 Antworten

9

Die Freuden der Fehlerbehandlung in der TPL :)

Sobald ein Task in einem eigenen Thread ausgeführt wird, ist alles, was darin passiert, bereits vom Aufrufer asynchron - einschließlich der Fehlerbehandlung

  1. Wenn Sie Ihre erste 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.
  2. Ausnahmen - Wenn Ihre innere Aufgabe fehlgeschlagen ist, wird die Eigenschaft 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.
  3. Was passiert, wenn eine Ausnahme ausgelöst wird ...
  

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.

Best Practices für TPL + Akka.NET

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.)

    
Aaronontheweb 16.02.2015, 22:08
quelle
6

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.

    
Roger Johansson 17.02.2015 05:52
quelle

Tags und Links