Sobes.tech
Middle+

Kann asynchroner Code synchron aufgerufen werden?

sobes.tech KI

Antwort von AI

Ja, es ist möglich, aber es kann zu Problemen führen, insbesondere zu Deadlocks.

Methoden, um asynchronen Code synchron aufzurufen:

  1. Verwendung der Eigenschaft Result oder der Methode Wait() an einem Task-Objekt.

    // Synchroner Aufruf einer asynchronen Methode
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Synchroner Zugriff auf das Ergebnis einer asynchronen Methode
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Verwendung von GetAwaiter().GetResult():

    // Synchroner Aufruf einer asynchronen Methode mit Ergebnis
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Nachteile dieses Ansatzes:

  • Deadlocks: Das häufigste Problem, besonders in UI-Threads oder ASP.NET-Kontexten mit Synchronisationskontext. Wait() und Result blockieren den aktuellen Thread, während die Aufgabe abgeschlossen wird. Wenn die asynchrone Methode versucht, den geblockierten Synchronisationskontext zu erfassen, entsteht ein Deadlock.
  • Leistungs- und Skalierungsverschlechterung: Das Blockieren von Threads anstelle der Verwendung asynchroner Operationen verbraucht mehr Ressourcen und verringert die Fähigkeit der Anwendung, mehrere gleichzeitige Anfragen zu verarbeiten (z.B. in Webanwendungen).
  • Nicht offensichtliches Verhalten: Das Mischen von asynchronem und synchronem Code kann den Ablauf schwer verständlich und debugbar machen.

In den meisten Fällen ist die richtige Vorgehensweise, await zu verwenden, um die asynchrone Ausführung fortzusetzen, oder, wenn asynchroner Code im Einstiegspunkt der Anwendung ausgeführt werden muss (z.B. Main), Task.Run() in Kombination mit Wait() zu verwenden oder Main asynchron zu machen, wenn die C#-Version dies unterstützt (async Task Main).

Beispiel für einen sicheren Aufruf von asynchronem Code aus einer synchronen Methode, bei Verwendung von Task.Run, um die Ausführung in den Threadpool zu verschieben:

// Sicherer Aufruf einer asynchronen Methode aus einem synchronen Kontext
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Sicherer Aufruf einer asynchronen Methode mit Ergebnis
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;