478 Stimmen

Wie ruft man sicher eine asynchrone Methode in C# auf, ohne await zu verwenden?

Ich habe eine async-Methode, die keine Daten zurückgibt:

public async Task MyAsyncMethod()
{
    // Führe einige Aufgaben asynchron aus, gebe keine Daten zurück
}

Ich rufe dies von einer anderen Methode aus auf, die einige Daten zurückgibt:

public string GetStringData()
{
    MyAsyncMethod(); // Dies erzeugt eine Warnung und unterdrückt Ausnahmen
    return "Hallo Welt";
}

Wenn MyAsyncMethod() aufgerufen wird, ohne darauf zu warten, wird in Visual Studio eine "Da dieser Aufruf nicht abgewartet wird, wird die aktuelle Methode weiterhin ausgeführt, bevor der Aufruf abgeschlossen ist"-Warnung angezeigt. Auf der Seite für diese Warnung heißt es:

Sie sollten die Warnung nur unterdrücken, wenn Sie sicher sind, dass Sie nicht auf das Abschließen des asynchronen Aufrufs warten möchten und dass die aufgerufene Methode keine Ausnahmen auslöst.

Ich bin mir sicher, dass ich nicht auf das Abschließen des Aufrufs warten möchte; Ich brauche es nicht oder habe keine Zeit dafür. Aber der Aufruf könnte Ausnahmen auslösen.

I ch bin ein paar Mal auf dieses Problem gestoßen, und ich bin sicher, dass es ein häufiges Problem ist, das eine gemeinsame Lösung haben muss.

Wie rufe ich sicher eine async-Methode auf, ohne auf das Ergebnis zu warten?

Aktualisierung:

Für Personen, die vorschlagen, dass ich einfach auf das Ergebnis warten soll, handelt es sich hier um Code, der auf eine Webanforderung auf unserem Webservice (ASP.NET Web-API) reagiert. Das Warten in einem UI-Kontext hält den UI-Thread frei, aber das Warten in einem Webanforderungsaufruf würde auf das Beenden des Tasks warten, bevor auf die Anforderung geantwortet wird, was die Antwortzeiten ohne Grund erhöht.

13voto

CharithJ Punkte 44196

Nicht die beste Praxis, du solltest versuchen, dies zu vermeiden.

Allerdings, um "Rufen Sie eine asynchrone Methode in C# ohne await auf" anzusprechen, können Sie die asynchrone Methode innerhalb eines Task.Run ausführen. Mit diesem Ansatz wird gewartet, bis MyAsyncMethod beendet ist.

public string GetStringData()
{
    Task.Run(()=> MyAsyncMethod()).Result;
    return "Hallo Welt";
}

await entpackt asynchron das Result Ihrer Aufgabe, während die Verwendung von Result blockieren würde, bis die Aufgabe abgeschlossen ist.

Wenn Sie es in einer Hilfsklasse verpacken möchten:

public static class AsyncHelper
{
    public static void Sync(Func func) => Task.Run(func).ConfigureAwait(false);

    public static T Sync(Func> func) => Task.Run(func).Result;

}

und rufen Sie es wie folgt auf

public string GetStringData()
{
    AsyncHelper.Sync(() => MyAsyncMethod());
    return "Hallo Welt";
}

9voto

Adam Diament Punkte 3550

Ich bin spät zur Party hier, aber es gibt eine tolle Bibliothek, die ich benutze, die in den anderen Antworten nicht erwähnt wurde

https://github.com/brminnick/AsyncAwaitBestPractices

Wenn Sie "Fire And Forget" benötigen, rufen Sie die Erweiterungsmethode auf die Aufgabe auf.

Die Übergabe der Aktion onException an den Aufruf stellt sicher, dass Sie das Beste aus beiden Welten erhalten - keine Notwendigkeit, auf die Ausführung zu warten und Ihre Benutzer langsamer zu machen, während Sie weiterhin die Möglichkeit haben, die Ausnahme in angemessener Weise zu behandeln.

In Ihrem Beispiel würden Sie es so verwenden:

   public string GetStringData()
    {
        MyAsyncMethod().SafeFireAndForget(onException: (exception) =>
                    {
                      //DO STUFF WITH THE EXCEPTION                    
                    }); 
        return "hello world";
    }

Es bietet auch awaitable AsyncCommands, die ICommand standardmäßig implementieren, was großartig für meine MVVM Xamarin-Lösung ist

2voto

TarmoPikaro Punkte 4208

Typischerweise gibt eine async-Methode die Task-Klasse zurück. Wenn Sie die Wait()-Methode oder die Result-Eigenschaft verwenden und der Code eine Ausnahme wirft - wird der Ausnahmetyp in AggregateException eingewickelt - dann müssen Sie Exception.InnerException abfragen, um die richtige Ausnahme zu lokalisieren.

Aber es ist auch möglich, stattdessen .GetAwaiter().GetResult() zu verwenden - es wird ebenfalls auf die async-Aufgabe warten, aber die Ausnahme nicht einpacken.

Hier ist also ein kurzes Beispiel:

public async Task MyMethodAsync()
{
}

public string GetStringData()
{
    MyMethodAsync().GetAwaiter().GetResult();
    return "test";
}

Sie möchten möglicherweise auch in der Lage sein, einen Parameter aus einer async-Funktion zurückzugeben - dies kann erreicht werden, indem Sie eine zusätzliche Action in die async-Funktion geben, zum Beispiel so:

public string GetStringData()
{
    return MyMethodWithReturnParameterAsync().GetAwaiter().GetResult();
}

public async Task MyMethodWithReturnParameterAsync()
{
    return "test";
}

Bitte beachten Sie, dass async-Methode typischerweise einen ASync-Suffix im Namen haben, nur um Kollisionen mit synchronen Funktionen mit dem gleichen Namen zu vermeiden. (z.B. FileStream.ReadAsync) - Ich habe die Funktionsnamen aktualisiert, um dieser Empfehlung zu folgen.

1voto

rhughes Punkte 8725

Ich denke, die Frage stellt sich, warum Sie das tun müssen? Der Grund für async in C# 5.0 ist, damit Sie auf ein Ergebnis warten können. Diese Methode ist eigentlich nicht asynchron, wird aber einfach zu einem Zeitpunkt aufgerufen, um den aktuellen Thread nicht zu sehr zu beeinträchtigen.

Vielleicht ist es besser, einen Thread zu starten und ihn von selbst beenden zu lassen.

1voto

haimb Punkte 321

Bei Technologien mit Message-Loops (bin mir nicht sicher, ob ASP eine davon ist), können Sie den Loop blockieren und Messages verarbeiten, bis die Aufgabe abgeschlossen ist, und ContinueWith verwenden, um den Code zu entsperren:

public void WaitForTask(Task task)
{
    DispatcherFrame frame = new DispatcherFrame();
    task.ContinueWith(t => frame.Continue = false));
    Dispatcher.PushFrame(frame);
}

Dieser Ansatz ähnelt dem Blockieren von ShowDialog und sorgt dennoch dafür, dass die Benutzeroberfläche reagiert.

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