Sobes.tech
Middle+

Je možné volať asynchrónny kód synchronne?

sobes.tech AI

Odpoveď od AI

Áno, je to možné, ale môže to viesť k problémom, najmä k deadlockom.

Spôsoby synchronného volania asynchrónneho kódu:

  1. Použitie vlastnosti Result alebo metódy Wait() objektu Task.

    // Synchronné volanie asynchrónnej metódy
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Získanie výsledku asynchrónnej metódy synchronne
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Použitie GetAwaiter().GetResult():

    // Synchronné volanie asynchrónnej metódy s získaním výsledku
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Nevýhody takéhoto prístupu:

  • Deadlocky: Najčastejší problém, najmä v UI vláknach alebo ASP.NET kontextoch so synchronization context-om. Wait() a Result blokujú aktuálne vlákno, čakajúc na dokončenie úlohy. Ak sa asynchrónna metóda pokúša zachytiť zablokovaný kontext synchronizácie na pokračovanie po await, dochádza k deadlocku.
  • Zhoršenie výkonu a škálovateľnosti: Blokovanie vlákien namiesto použitia asynchrónnych operácií spotrebúva viac zdrojov a znižuje schopnosť aplikácie spracovať veľké množstvo súčasných požiadaviek (napríklad v webových aplikáciách).
  • Nejasné správanie: Miešanie asynchrónneho a synchronného kódu môže spôsobiť, že tok vykonávania programu bude zložitý na pochopenie a ladenie.

Vo väčšine prípadov je správny prístup používať await na pokračovanie asynchrónneho vykonávania alebo, ak je potrebné vykonať asynchrónny kód v vstupe do aplikácie (napríklad Main), použiť Task.Run() v kombinácii s Wait() alebo vytvoriť Main ako asynchrónny, ak to verzia C# podporuje (async Task Main).

Príklad bezpečného volania asynchrónneho kódu zo synchronickej metódy pomocou Task.Run na presun vykonávania do poolu vlákien:

// Bezpečné volanie asynchrónnej metódy zo synchronického kontextu
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Bezpečné volanie asynchrónnej metódy s výsledkom
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;