c# without async/await-wann soll ein Task void void zurückgegeben werden?




c# wait for async method (4)

1) Normalerweise möchten Sie eine Task . Die Hauptausnahme sollte sein, wenn Sie einen void Rückgabetyp (für Ereignisse) benötigen . Wenn es keinen Grund gibt, den Anrufer nicht await Ihre Aufgabe await , warum dann ablehnen?

2) async Methoden, die void sind in einem anderen Aspekt besonders: Sie stellen asynchrone Vorgänge auf oberster Ebene dar und haben zusätzliche Regeln, die ins Spiel kommen, wenn Ihre Aufgabe eine Ausnahme zurückgibt. Der einfachste Weg ist, den Unterschied mit einem Beispiel zu zeigen:

static async void f()
{
    await h();
}

static async Task g()
{
    await h();
}

static async Task h()
{
    throw new NotImplementedException();
}

private void button1_Click(object sender, EventArgs e)
{
    f();
}

private void button2_Click(object sender, EventArgs e)
{
    g();
}

private void button3_Click(object sender, EventArgs e)
{
    GC.Collect();
}

Die Ausnahme wird immer "beobachtet". Eine Ausnahme, die eine asynchrone Methode auf oberster Ebene zurücklässt, wird einfach wie jede andere unbehandelte Ausnahme behandelt. Die Ausnahme von g wird niemals beobachtet. Wenn der Garbage Collector zum Bereinigen der Aufgabe kommt, sieht er, dass die Aufgabe zu einer Ausnahme geführt hat und niemand die Ausnahme behandelt hat. Wenn das passiert, wird der TaskScheduler.UnobservedTaskException Handler ausgeführt. Du solltest das niemals zulassen. Um Ihr Beispiel zu verwenden,

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}

Ja, benutze async und await hier, sie stellen sicher, dass deine 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

Unter welchen Szenarien möchte man verwenden?

public async Task AsyncMethod(int num)

Anstatt von

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.

Außerdem sind in der folgenden Methode die Schlüsselwörter async und await unnötig?

  public static async void AsyncMethod2(int num)
    {
        await Task.Factory.StartNew(() => Thread.Sleep(num));
    }

Ich denke, Sie können async void zum Starten von Hintergrundoperationen verwenden, solange Sie darauf achten, Ausnahmen zu erfassen. Gedanken?

class Program {

    static bool isFinished = false;

    static void Main(string[] args) {

        // Kick off the background operation and don't care about when it completes
        BackgroundWork();

        Console.WriteLine("Press enter when you're ready to stop the background operation.");
        Console.ReadLine();
        isFinished = true;
    }

    // Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
    static async void BackgroundWork() {
        // It's important to catch exceptions so we don't crash the appliation.
        try {
            // This operation will end after ten interations or when the app closes. Whichever happens first.
            for (var count = 1; count <= 10 && !isFinished; count++) {
                await Task.Delay(1000);
                Console.WriteLine($"{count} seconds of work elapsed.");
            }
            Console.WriteLine("Background operation came to an end.");
        } catch (Exception x) {
            Console.WriteLine("Caught exception:");
            Console.WriteLine(x.ToString());
        }
    }
}

Ich bin auf diesen sehr nützlichen Artikel über async und void von Jérôme Laban gestoßen: http://www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.aspx

Die Quintessenz ist, dass ein async+void das System zum Absturz bringen kann und normalerweise nur auf den Event-Handlern auf der UI-Seite verwendet werden sollte.

Der Grund dafür ist der Synchronisationskontext, der vom AsyncVoidMethodBuilder verwendet wird und in diesem Beispiel keins ist. Wenn kein Umgebungssynchronisationskontext vorhanden ist, wird jede Ausnahme, die vom Hauptteil einer asynchronen Void-Methode nicht behandelt wird, im ThreadPool erneut aufgerufen. Während es scheinbar keinen anderen logischen Ort gibt, an dem diese Art von unbehandeltem Exception ausgelöst werden könnte, ist der unglückliche Effekt, dass der Prozess beendet wird, weil nicht behandelte Ausnahmen auf dem ThreadPool den Prozess seit .NET 2.0 effektiv beenden. Sie können alle unbehandelten Ausnahmen mit dem Ereignis AppDomain.UnhandledException abfangen, aber es gibt keine Möglichkeit, den Prozess von diesem Ereignis wiederherzustellen.

Beim Schreiben von UI-Ereignishandlern sind asynchrone void-Methoden irgendwie schmerzlos, da Ausnahmen genauso behandelt werden wie nicht-asynchrone Methoden; Sie werden auf den Dispatcher geworfen. Es gibt eine Möglichkeit, sich von solchen Ausnahmen zu erholen, was in den meisten Fällen mehr als korrekt ist. Außerhalb von UI-Ereignishandlern sind async void-Methoden jedoch irgendwie gefährlich zu verwenden und möglicherweise nicht so einfach zu finden.


Ich habe eine klare Vorstellung von diesen Aussagen bekommen.

  1. Asynchrone Void-Methoden haben unterschiedliche Fehlerbehandlungssemantiken. Wenn eine Ausnahme aus einer asynchronen Task- oder asynchronen Task-Methode ausgelöst wird, wird diese Ausnahme erfasst und im Task-Objekt platziert. Bei asynchronen Void-Methoden gibt es kein Task-Objekt, daher werden Ausnahmen, die aus einer asynchronen void-Methode ausgelöst werden, direkt im SynchronizationContext ausgelöst (SynchronizationContext steht für einen Ort, an dem der Code ausgeführt wird.), Der bei der async void-Methode aktiv war gestartet

Ausnahmen von einer asynchronen Void-Methode können nicht mit Catch abgefangen werden

private async void ThrowExceptionAsync()
{
  throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
  try
  {
    ThrowExceptionAsync();
  }
  catch (Exception)
  {
    // The exception is never caught here!
    throw;
  }
}

Diese Ausnahmen können mit AppDomain.UnhandledException oder einem ähnlichen Catch-All-Ereignis für GUI / ASP.NET-Anwendungen beobachtet werden, aber die Verwendung dieser Ereignisse für die reguläre Ausnahmebehandlung ist ein Rezept für die Unerreichbarkeit (es stürzt die Anwendung ab).

  1. Asynchrone Void-Methoden haben unterschiedliche Komponentensemantiken. Asynchrone Methoden, die eine Aufgabe oder Aufgabe zurückgeben, können leicht mit Hilfe von "Warten", "Aufgabe.WhenAny", "Aufgabe.WhenAll" usw. erstellt werden. Asynchrone Methoden, die void zurückgeben, bieten keine einfache Möglichkeit, den ausgefüllten aufrufenden Code zu benachrichtigen. Es ist einfach, mehrere asynchrone void-Methoden zu starten, aber es ist nicht einfach festzustellen, wann sie abgeschlossen sind. Asynchrone Void-Methoden melden ihren SynchronizationContext, wenn sie gestartet und beendet werden, aber ein benutzerdefinierter SynchronizationContext ist eine komplexe Lösung für regulären Anwendungscode.

  2. Die Async Void-Methode ist nützlich, wenn Sie synchrone Ereignisbehandlungsroutinen verwenden, da sie ihre Ausnahmen direkt im SynchronizationContext auslösen, ähnlich wie sich synchrone Ereignisbehandlungsroutinen verhalten

Weitere Informationen finden Sie unter https://msdn.microsoft.com/en-us/magazine/jj991977.aspx





.net-4.5