Sollte meine asynchrone Aufgabenbibliothek Ausnahmen leise verschlucken?

10

Ich habe gerade erfahren, dass .NET 4.5 eine Änderung in der Behandlung von Ausnahmen in a eingeführt hat Task. Sie werden nämlich leise unterdrückt.

Die offizielle Begründung dafür scheint zu sein: "Wir wollten unerfahrenen Entwicklern gegenüber freundlicher sein":

In .NET 4.5 haben Aufgaben eine deutlich höhere Bedeutung als in .NET 4, da sie als Teil der neuen asynchronen Funktionen, die von den Sprachen unterstützt werden, in die Sprachen C # und Visual Basic integriert sind. Dies verschiebt Aufgaben aus dem Bereich erfahrener Entwickler in den Bereich aller. Infolgedessen führt dies auch zu einer Reihe neuer Kompromisse hinsichtlich der Einhaltung der Ausnahmebehandlung.

( Quelle )

Ich habe gelernt zu vertrauen, dass viele der Entscheidungen in .NET von Leuten getroffen wurden, die wirklich wissen, was sie tun, und es gibt normalerweise einen sehr guten Grund für die Dinge, die sie entscheiden. Aber dieser entgeht mir.

Wenn ich meine eigene asynchrone Aufgabenbibliothek entwerfe, welchen Vorteil hat das Verschlucken von Ausnahmen, die die Entwickler des Frameworks gesehen haben und die ich nicht sehe?

Roman Starkov
quelle
4
+1. Gute Frage, angesichts der Tatsache, dass das Nicht-Weitergeben von Ausnahmen, die Sie nicht verarbeiten können, auch im asynchronen Kontext eine schlechte Praxis ist. Auch das Argument über unerfahrene Entwickler ist meiner Meinung nach ziemlich lahm. Was wäre für Anfänger umständlicher als ein Code, der nicht nur nicht funktioniert, sondern auch keinerlei Ausnahmen auslöst?
Arseni Mourzenko
@MainMa Genau meine Gedanken, aber ich habe mich vorher geirrt (als sich herausstellte, dass sie tatsächlich einen sehr guten, aber nicht offensichtlichen Grund hatten), also dachte ich, ich würde fragen.
Roman Starkov
2
Wow, ich bin froh, dass du das gepostet hast, nur weil es das erste ist, von dem ich gehört habe. und es verstößt definitiv gegen POLA . Sie haben Recht, dass diese Leute wirklich wissen, was sie tun, also bin ich aufrichtig neugierig, welche Argumentation dahinter steckt ... Ich frage mich, ob es einen technischeren Grund gibt, der auf der Implementierung von Async basiert und wie sich Ausnahmen verbreiten würden als Boden wird an eine Coroutine übergeben ..
Jimmy Hoffa

Antworten:

2

Für das, was es wert ist, gibt das Dokument, mit dem Sie verlinkt haben, einen Beispielfall als Begründung:

Task op1 = FooAsync(); 
Task op2 = BarAsync(); 
await op1; 
await op2;

In diesem Code startet der Entwickler zwei asynchrone Operationen, die parallel ausgeführt werden sollen, und wartet dann asynchron auf jede mit der neuen Funktion zum Warten auf Sprache ... [C] Überlegen Sie, was passieren wird, wenn sowohl op1 als auch op2 fehlerhaft sind. Das Warten auf op1 verbreitet die Ausnahme von op1, und daher wird op2 niemals erwartet. Infolgedessen wird die Ausnahme von op2 nicht beachtet, und der Prozess würde schließlich abstürzen.

Um Entwicklern das Schreiben von asynchronem Code basierend auf Aufgaben zu erleichtern, ändert .NET 4.5 das Standardausnahmeverhalten für nicht beobachtete Ausnahmen. Während nicht beobachtete Ausnahmen weiterhin dazu führen, dass das Ereignis UnobservedTaskException ausgelöst wird (dies wäre eine wichtige Änderung), stürzt der Prozess standardmäßig nicht ab. Vielmehr wird die Ausnahme nach dem Auslösen des Ereignisses gegessen, unabhängig davon, ob ein Ereignishandler die Ausnahme beobachtet.

Das überzeugt mich nicht. Es beseitigt die Möglichkeit eines eindeutigen, aber schwer zu verfolgenden Fehlers (mysteriöser Programmabsturz, der lange nach dem eigentlichen Fehler auftreten kann), ersetzt ihn jedoch durch die Möglichkeit eines völlig stillen Fehlers, der später zu einem ebenso schwer zu verfolgenden Problem werden kann in Ihrem Programm. Das scheint mir eine zweifelhafte Entscheidung zu sein.

Das Verhalten ist konfigurierbar - aber natürlich werden 99% der Entwickler nur das Standardverhalten verwenden, ohne an dieses Problem zu denken. Was sie als Standard ausgewählt haben, ist also eine große Sache.


quelle
Aber Sie tun eine normale Ausnahme erhalten op1, nicht wahr? Wenn dieser unbehandelt bleibt, wird er den Prozess zum Erliegen bringen, oder?
Timwi
1
@ Timwi, so wie ich es verstehe, würde weder op1die Ausnahme noch op2die Ausnahme das Programm zum Erliegen bringen. Der Vorteil ist, dass Sie die Möglichkeit haben, beide zu beobachten. Wenn Sie dies nicht tun, werden beide verschluckt. Ich könnte mich jedoch irren.
Ich bin wirklich überrascht, dass sie es so wichtig finden, dass Sie beide "beobachten". Wenn Sie sie "beobachten" möchten, fangen Sie sie und melden ihr Auftreten über das Aufgabenergebnis! ... Stimmen Sie Ihrer Argumentation zu, +1
Roman Starkov
2

TL; DR - Nein , Sie sollten Ausnahmen nicht einfach leise ignorieren.


Schauen wir uns die Annahmen an.

  • Dein blinder Glaube

Ich habe gelernt zu vertrauen, dass viele der Entscheidungen in .NET von Leuten getroffen wurden, die wirklich wissen, was sie tun, und es gibt normalerweise einen sehr guten Grund für die Dinge, die sie entscheiden. Aber dieser entgeht mir.

MS hat zweifellos einige wirklich brillante Mitarbeiter. Sie haben auch eine Reihe von Managern und Führungskräften, die ... ahnungslos sind und durchweg schlechte Entscheidungen treffen. So sehr wir dem Märchen des technisch versierten Wissenschaftlers glauben möchten, der die Produktentwicklung vorantreibt, ist die Realität weitaus düsterer.

Mein Punkt ist, wenn Ihr Instinkt Ihnen sagt, dass etwas möglicherweise nicht stimmt, besteht eine gute Chance (und ein früherer Präzedenzfall), dass es falsch ist.

  • Dass dies ein technisches Problem ist

Der Umgang mit Ausnahmen ist in diesem Fall eine Entscheidung über menschliche Faktoren, keine technische Entscheidung. Eine Ausnahme ist locker ein Fehler. Die Darstellung des Fehlers liefert dem Endbenutzer wichtige Informationen, auch wenn diese schlecht formatiert sind. Es ist nämlich etwas schief gelaufen.

Betrachten Sie diese hypothetische Konversation zwischen einem Endbenutzer und einem Entwickler.

Benutzer: Die App ist kaputt.
Dev: Was ist kaputt?
Benutzer: Ich weiß nicht, ich klicke auf die Schaltfläche und nichts passiert.
Dev: Was meinst du damit, dass nichts passiert?
Benutzer: Schau, ich klicke, ich warte und ich warte und ich warte und nichts ... es ist offensichtlich kaputt.

Unser armer, glücklicherweise hypothetischer Entwickler muss jetzt herausfinden, was in der Kette der Ereignisse schief gelaufen ist. Wo war es?
Event-Handler-Benachrichtigung -> Routine zur Behandlung des Ereignisses -> Vom Handler ausgelöste Methode -> Beginn des asynchronen Aufrufs -> die 7 Schichten des OSI-Netzwerks -> physische Übertragung -> Sichern der 7 Schichten des OSI-Netzwerks -> Empfangsdienst -> vom Dienst aufgerufene Methode -> ... -> vom Dienst gesendete Antwort zurückgeben -> .... -> asynchrone Quittung -> Verarbeitung der asynchronen Antwort -> ...

Und bitte beachten Sie, dass ich dort einige mögliche Fehlerpfade beschönigt habe.


Nachdem ich einige der zugrunde liegenden Annahmen angesprochen habe, wird mir klarer, warum es eine schlechte Idee ist, Ausnahmen stillschweigend zu unterdrücken. Eine Ausnahme und die damit verbundene Fehlermeldung sind ein Schlüsselindikator für die Benutzer, dass ein Fehler aufgetreten ist. Selbst wenn die Nachricht für den Endbenutzer bedeutungslos ist, können die eingebetteten Informationen für den Entwickler hilfreich sein, um zu verstehen, was schief gelaufen ist. Wenn sie Glück haben, führt die Nachricht sogar zur Lösung.

Ich denke, ein Teil des Problems hier ist, dass eine falsch behandelte Ausnahme Ihre Anwendung zum Absturz bringt. Durch Unterdrücken der Ausnahmen stürzt die Anwendung nicht ab. Dies hat jedoch eine gewisse Gültigkeit, da der asynchrone Punkt darin besteht, der Anwendung zu ermöglichen, weiter zu arbeiten, während Daten abgerufen werden. Es ist keine logische Erweiterung zu sagen, dass ein Fehler beim Abrufen auch die Anwendung nicht zum Absturz bringen sollte, wenn Sie während des Wartens auf die Ergebnisse weiterarbeiten könnten - der asynchrone Aufruf wird implizit als nicht wichtig genug deklariert, um die Anwendung zu beenden.

Es ist also eine Lösung, aber es löst das falsche Problem. Es ist nicht so aufwendig, einen Wrapper für die Ausnahmebehandlung bereitzustellen, damit die Anwendung weiterhin ausgeführt werden kann. Die Ausnahme wird abgefangen, eine Fehlermeldung wird auf dem Bildschirm angezeigt oder protokolliert, und die Anwendung kann weiter ausgeführt werden. Das Unterdrücken der Ausnahme bedeutet, dass das Ignorieren von Fehlern A-OK ist und dass Ihre Tests sicherstellen, dass Ausnahmen sowieso nie ins Feld gelangen.

Meine abschließende Einschätzung ist also, dass dies ein halbherziger Versuch ist, ein Problem zu lösen, das dadurch entsteht, dass Menschen in ein asynchrones Modell gedrängt werden, wenn sie nicht bereit waren, ihr Denken auf diesen Ansatz zu verlagern.


quelle