Unter welchen Szenarien möchte man verwenden
public async Task AsyncMethod(int num)
anstatt
public async void AsyncMethod(int num)
Das einzige Szenario, an das ich denken kann, ist, wenn Sie die Aufgabe benötigen, um ihren Fortschritt verfolgen zu können.
Sind bei der folgenden Methode außerdem die Schlüsselwörter asynchron und warten unnötig?
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
c#
asynchronous
.net-4.5
user981225
quelle
quelle
Foo()
werden solltenFooAsync()
.Thread.Sleep
für Ihre Aufgaben verwenden sollten, die Sieawait Task.Delay(num)
stattdessen verwenden solltenTask.Delay
ist nichtTask.AsyncDelay
, dass alle Methoden auf Aufgabe Async sindasync void
stattdessen als deklariert wurdeasync Task
. Die Methode stürzte ab, weil ein als Mitglied des Controllers deklariertes Entity Framework-Kontextobjekt verwendet wurde, bevor die Ausführung der Methode abgeschlossen war. Das Framework hat den Controller entsorgt, bevor die Ausführung seiner Methode abgeschlossen ist. Ich habe die Methode in async Task geändert und es hat funktioniert.Antworten:
1) Normalerweise möchten Sie a zurückgeben
Task
. Die Hauptausnahme sollte sein, wenn Sie einen Rückgabetyp benötigenvoid
(für Ereignisse). Wenn es keinen Grund gibt, dem Anruferawait
Ihre Aufgabe zu verweigern , warum nicht?2)
async
Rückgabemethodenvoid
sind in einem anderen Aspekt etwas Besonderes: Sie stellen asynchrone Operationen der obersten Ebene dar und enthalten zusätzliche Regeln, die zum Tragen kommen, wenn Ihre Aufgabe eine Ausnahme zurückgibt. Der einfachste Weg, den Unterschied zu zeigen, ist anhand eines Beispiels:f
Die Ausnahme wird immer "beobachtet". Eine Ausnahme, die eine asynchrone Methode der obersten Ebene hinterlässt, wird einfach wie jede andere nicht behandelte Ausnahme behandelt.g
Die Ausnahme wird nie beachtet. Wenn der Garbage Collector die Aufgabe bereinigt, sieht er, dass die Aufgabe zu einer Ausnahme geführt hat und niemand die Ausnahme behandelt hat. In diesem Fall wird derTaskScheduler.UnobservedTaskException
Handler ausgeführt. Sie sollten dies niemals zulassen. Um Ihr Beispiel zu verwenden,Ja, verwenden Sie
async
undawait
hier stellen sie sicher, dass Ihre Methode immer noch korrekt funktioniert, wenn eine Ausnahme ausgelöst wird.Weitere Informationen finden Sie unter: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
quelle
f
stattg
in meinem Kommentar. Die Ausnahme vonf
wird an die übergebenSynchronizationContext
.g
wird ausgelöstUnobservedTaskException
,UTE
stürzt aber nicht mehr ab, wenn er nicht behandelt wird. Es gibt Situationen, in denen es akzeptabel ist, solche "asynchronen Ausnahmen" zu haben, die ignoriert werden.WhenAny
mit mehrerenTask
s Ausnahmen haben. Sie müssen oft nur den ersten behandeln und möchten die anderen oft ignorieren.WhenAny
ob es in Ordnung ist, die anderen Ausnahmen zu ignorieren: Der Hauptanwendungsfall, den ich dafür habe, wartet immer noch auf die verbleibenden Aufgaben, wenn sie abgeschlossen sind mit oder ohne Ausnahme.Ich bin auf diesen sehr nützlichen Artikel über Jérôme Laban gestoßen
async
und habe ihnvoid
geschrieben: https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void .htmlDie Quintessenz ist, dass ein
async+void
System abstürzen kann und normalerweise nur auf den UI-seitigen Ereignishandlern verwendet werden sollte.quelle
Ich habe eine klare Vorstellung von diesen Aussagen.
Ausnahmen von einer Async Void-Methode können nicht mit Catch erfasst werden
Diese Ausnahmen können mit AppDomain.UnhandledException oder einem ähnlichen Sammelereignis für GUI / ASP.NET-Anwendungen beobachtet werden. Die Verwendung dieser Ereignisse für die reguläre Ausnahmebehandlung ist jedoch ein Rezept für die Nichtwartbarkeit (die Anwendung stürzt ab).
Asynchrone Void-Methoden haben unterschiedliche Kompositionssemantiken. Asynchrone Methoden, die Task oder Task zurückgeben, können einfach mit await, Task.WhenAny, Task.WhenAll usw. erstellt werden. Asynchrone Methoden, die void zurückgeben, bieten keine einfache Möglichkeit, den abgeschlossenen Aufrufcode zu benachrichtigen. Es ist einfach, mehrere asynchrone Void-Methoden zu starten, aber es ist nicht einfach festzustellen, wann sie fertig sind. Async void-Methoden benachrichtigen ihren SynchronizationContext, wenn sie gestartet und beendet werden. Ein benutzerdefinierter SynchronizationContext ist jedoch eine komplexe Lösung für regulären Anwendungscode.
Die asynchrone Void-Methode ist nützlich, wenn Sie den synchronen Ereignishandler verwenden, da sie ihre Ausnahmen direkt im SynchronizationContext auslösen. Dies ähnelt dem Verhalten synchroner Ereignishandler
Weitere Informationen finden Sie unter diesem Link: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
quelle
Das Problem beim Aufrufen von async void ist, dass Sie die Aufgabe nicht einmal zurückerhalten und nicht wissen können, wann die Aufgabe der Funktion abgeschlossen ist (siehe https://blogs.msdn.microsoft.com/oldnewthing/20170720-00/). p = 96655 )
Hier sind die drei Möglichkeiten, eine asynchrone Funktion aufzurufen:
quelle
Ich denke, Sie können damit auch
async void
Hintergrundoperationen starten, solange Sie darauf achten, Ausnahmen zu erwischen. Gedanken?quelle
Meine Antwort ist einfach: Sie können die Methode der Leere nicht abwarten
Wenn die Methode also asynchron ist, ist es besser, auf sie zu warten, da Sie den asynchronen Vorteil verlieren können.
quelle
Laut Microsoft-Dokumentation sollte NIEMALS verwendet werden
async void
quelle