Sobes.tech
Middle+

Lehet szinkron módon hívni aszinkron kódot?

sobes.tech MI

Válasz az MI-től

Igen, lehetséges, de problémákhoz vezethet, különösen deadlockokhoz.

Az aszinkron kód szinkron hívásának módjai:

  1. A Result tulajdonság vagy a Wait() metódus használata egy Task objektumon.

    // Aszinkron metódus szinkron hívása
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Az aszinkron metódus eredményének szinkron lekérése
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. A GetAwaiter().GetResult() használata:

    // Szinkron hívás eredménnyel
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Ennek a megközelítésnek hátrányai:

  • Deadlock: A leggyakoribb probléma, különösen UI szálakon vagy ASP.NET kontextusokban, ahol a szinkronizációs kontextushoz kötött. A Wait() és a Result blokkolják az aktuális szálat, várva a feladat befejezését. Ha az aszinkron metódus megpróbálja elkapni a blokkolt szinkronizációs kontextust a await utáni folytatáshoz, deadlock keletkezik.
  • Teljesítmény- és skálázhatóságcsökkenés: A szálak blokkolása az aszinkron műveletek helyett több erőforrást igényel, és csökkenti az alkalmazás képességét, hogy több kérés egyidejűleg legyen kezelve (például webalkalmazásokban).
  • Nem nyilvánvaló viselkedés: Az aszinkron és szinkron kód keverése megnehezítheti a program futásának megértését és hibakeresését.

A legtöbb esetben a helyes megközelítés az await használata az aszinkron végrehajtás folytatásához, vagy ha az aszinkron kódot az alkalmazás belépési pontján (például Main) kell futtatni, akkor Task.Run() használata Wait()-el vagy az Main aszinkronná tétele, ha a C# verzió támogatja (async Task Main).

Biztonságos példa az aszinkron kód szinkron hívására, Task.Run használatával, hogy a végrehajtást a szálak pooljára helyezzük:

// Biztonságos aszinkron hívás szinkron kontextusból
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Biztonságos aszinkron hívás eredménnyel
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;