Sobes.tech
Middle+

Lze volat asynchronní kód synchronně?

sobes.tech AI

Odpověď od AI

Ano, je to možné, ale může to způsobit problémy, zejména deadlocky.

Způsoby, jak synchronně volat asynchronní kód:

  1. Použití vlastnosti Result nebo metody Wait() na objektu Task.

    // Synchronní volání asynchronní metody
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Získání výsledku asynchronní metody synchronně
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Použití GetAwaiter().GetResult():

    // Synchronní volání s výsledkem
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Nevýhody tohoto přístupu:

  • Deadlock: Nejčastější problém, zejména v UI vláknech nebo v ASP.NET kontextech s synchronizačním kontextem. Wait() a Result blokují aktuální vlákno, čekají na dokončení úkolu. Pokud se asynchronní metoda pokusí zachytit zablokovaný kontext pro pokračování po await, vznikne deadlock.
  • Zhoršení výkonu a škálovatelnosti: Blokování vláken místo použití asynchronních operací spotřebovává více zdrojů a snižuje schopnost aplikace zpracovávat více požadavků současně (například ve webových aplikacích).
  • Nezřetelné chování: Míchání asynchronního a synchronního kódu může ztížit pochopení a ladění toku programu.

Ve většině případů je správný přístup používat await k pokračování asynchronního provádění nebo, pokud je nutné spustit asynchronní kód v vstupním bodě aplikace (například Main), použít Task.Run() ve spojení s Wait() nebo udělat Main asynchronní, pokud to verze C# podporuje (async Task Main).

Příklad bezpečného volání asynchronního kódu ze synchronní metody s použitím Task.Run k přesunutí provádění do thread poolu:

// Bezpečné volání asynchronní metody ze synchronního kontextu
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Bezpečné volání asynchronní metody s výsledkem
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;