715 Stimmen

async/await - wann einen Task zurückgeben vs. void?

Unter welchen Umständen sollte man die

public async Task AsyncMethod(int num)

anstelle von

public async void AsyncMethod(int num)

Das einzige Szenario, das ich mir vorstellen kann, ist, wenn Sie die Aufgabe benötigen, um ihren Fortschritt verfolgen zu können.

Sind in der folgenden Methode die Schlüsselwörter async und await überflüssig?

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

47 Stimmen

@Fred Meistens, aber nicht immer. Dies ist nur die Konvention und die akzeptierten Ausnahmen von dieser Konvention sind ereignisbasierte Klassen oder Schnittstellenverträge, siehe MSDN . So sollten Sie beispielsweise gängige Ereignis-Handler wie Button1_Click nicht umbenennen.

18 Stimmen

Nur eine Anmerkung, die Sie nicht verwenden sollten Thread.Sleep mit Ihren Aufgaben sollten Sie await Task.Delay(num) stattdessen

78 Stimmen

@fred Ich stimme damit nicht überein, IMO Hinzufügen einer async Suffix sollte nur verwendet werden, wenn Sie eine Schnittstelle mit sowohl sync und async Optionen bereitstellen. Dinge mit async zu benennen, wenn es nur eine Absicht gibt, ist sinnlos. Beispiel Task.Delay ist nicht Task.AsyncDelay da alle Methoden der Aufgabe Async sind

563voto

  1. Normalerweise würden Sie eine Task . Die wichtigste Ausnahme sollte sein, wenn Sie brauchen zu haben void Rückgabetyp (für Ereignisse). Wenn es keinen Grund gibt, der es verbietet, dass der Aufrufer await Ihre Aufgabe, warum sollten Sie sie nicht zulassen?

  2. async Methoden, die Folgendes zurückgeben void sind in anderer Hinsicht besonders: Sie stellen asynchrone Vorgänge der obersten Ebene und haben zusätzliche Regeln, die zum Tragen kommen, wenn Ihre Aufgabe eine Ausnahme zurückgibt. Am einfachsten lässt sich der Unterschied anhand eines Beispiels verdeutlichen:

    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(); }

f Ausnahme wird immer "beobachtet". Eine Ausnahme, die eine asynchrone Methode der obersten Ebene verlässt, wird einfach wie jede andere unbehandelte Ausnahme behandelt. g wird nie beachtet. Wenn der Garbage Collector kommt, um die Aufgabe aufzuräumen, sieht er, dass die Aufgabe zu einer Ausnahme geführt hat und niemand die Ausnahme behandelt hat. Wenn das passiert, wird die TaskScheduler.UnobservedTaskException Handler läuft. Dies sollten Sie niemals zulassen. Um Ihr Beispiel zu verwenden,

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

Ja, verwenden Sie async y await stellen sie sicher, dass Ihre Methode auch dann noch korrekt funktioniert, wenn eine Ausnahme ausgelöst wird.

Für weitere Informationen siehe: https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

63voto

user8128167 Punkte 5968

Das Problem beim Aufruf von async void ist, dass

erhalten Sie nicht einmal die Aufgabe zurück. Sie haben keine Möglichkeit zu wissen, wann die Aufgabe der Funktion abgeschlossen ist. -- Crashkurs in async und await | The Old New Thing

Hier sind die drei Möglichkeiten, eine asynchrone Funktion aufzurufen:

async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }

In allen Fällen wird die Funktion in eine Kette von Aufgaben umgewandelt. Der Unterschied besteht darin, was die Funktion zurückgibt.

Im ersten Fall gibt die Funktion eine Aufgabe zurück, die schließlich das t erzeugt.

Im zweiten Fall gibt die Funktion eine Aufgabe zurück, die kein Produkt hat, aber Sie können aber Sie können trotzdem auf sie warten, um zu erfahren, wann sie abgeschlossen ist.

Der dritte Fall ist der unangenehme. Der dritte Fall ist wie der zweite Fall, außer dass dass Sie nicht einmal die Aufgabe zurückbekommen. Sie haben keine Möglichkeit zu wissen, wann die Aufgabe der Funktion abgeschlossen ist.

Der async void Fall ist ein "Feuer und vergessen": Man startet die Aufgabenkette, aber man kümmert sich nicht darum, wann sie abgeschlossen ist. beendet ist. Wenn die Funktion zurückkehrt, wissen Sie nur, dass alles bis zum ersten await ausgeführt wurde. Alles nach dem ersten await wird zu einem unbestimmten Zeitpunkt in der Zukunft ausgeführt, auf den Sie keinen zu dem Sie keinen Zugang haben.

62voto

Davide Icardi Punkte 11211

Ich bin auf diesen sehr nützlichen Artikel gestoßen über async y void geschrieben von Jérôme Laban: https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

Das Fazit ist, dass ein async+void kann das System zum Absturz bringen und sollte in der Regel nur für die UI-seitigen Event-Handler verwendet werden.

Der Grund dafür ist der Synchronisierungskontext, der von der AsyncVoidMethodBuilder verwendet wird, der in diesem Beispiel keiner ist. Wenn es keinen umgebenden Synchronisationskontext gibt, wird jede Ausnahme, die nicht von einer asynchronen Void-Methode nicht behandelt wird, im ThreadPool erneut ausgelöst. Während es scheinbar keinen anderen logischen Ort gibt, an dem diese Art von unbehandelten Ausnahme ausgelöst werden könnte, besteht die unglückliche Folge darin, dass der Prozess abgebrochen wird, weil unbehandelte Ausnahmen im ThreadPool den Prozess seit .NET 2.0 effektiv beenden. Sie können abfangen alle unbehandelten Ausnahmen mit dem Ereignis AppDomain.UnhandledException abfangen, aber es gibt keine Möglichkeit, den Prozess aus diesem Ereignis wiederherzustellen.

Beim Schreiben von UI-Ereignishandlern sind async void-Methoden irgendwie schmerzlos, weil Ausnahmen genauso behandelt werden wie bei nicht asynchronen Methoden behandelt werden; sie werden im Dispatcher ausgelöst. Es gibt eine Möglichkeit, sich von solchen Ausnahmen zu erholen, was in den meisten Fällen mehr als für die meisten Fälle. Außerhalb von UI-Ereignishandlern sind jedoch async void Methoden jedoch gefährlich und nicht so leicht zu finden.

14voto

bboyle1234 Punkte 4719

Ich denke, Sie können Folgendes verwenden async void auch für das Starten von Hintergrundoperationen, solange Sie darauf achten, Ausnahmen abzufangen. Was denken Sie?

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());
        }
    }
}

3voto

Amit Bisht Punkte 4653

Eine kurze Erklärung:
async Task<T> method() können verwendet werden zu warten, bis die Ausführung abgeschlossen ist, und es wird return value vom Typ T
async Task method() können verwendet werden zu warten, bis die Ausführung abgeschlossen ist, sondern keine Daten es zurückgegeben
async void method() kann nicht erwartet werden y es werden keine Daten zurückgegeben [Beispiel: asynchrone Ereignisausführung]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X