Sobes.tech
Middle+

Може ли асинхрона код да се позове синхроно?

sobes.tech АИ

Одговор од АИ

Da, može se, ali to može dovesti do problema, posebno do deadlockova.

Načini sinhronog pozivanja asinhronog koda:

  1. Korišćenje svojstva Result ili metode Wait() objekta Task.

    // Sinhroni poziv asinhrone metode
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Dobijanje rezultata asinhrone metode sinhrono
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Korišćenje GetAwaiter().GetResult():

    // Sinhroni poziv asinhrone metode sa dobijanjem rezultata
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Nedostaci takvog pristupa:

  • Deadlockovi: Najčešći problem, posebno u UI nitima ili ASP.NET kontekstima sa synchronization context-om. Wait() i Result blokiraju trenutnu nit, čekajući završetak zadatka. Ako asinhrona metoda pokušava da uhvati blokirani kontekst sinhronizacije za nastavak nakon await, dolazi do deadlocka.
  • Poboljšanje performansi i skalabilnosti: Blokiranje niti umesto korišćenja asinhronih operacija troši više resursa i smanjuje sposobnost aplikacije da obrađuje veliki broj istovremenih zahteva (npr. u web aplikacijama).
  • Nejasno ponašanje: Mešanje asinhronog i sinhronog koda može učiniti tok izvršenja programa složenim za razumevanje i otklanjanje grešaka.

U većini slučajeva, ispravan pristup je korišćenje await za nastavak asinhronog izvršenja ili, ako je potrebno izvršiti asinhroni kod u tački ulaska u aplikaciju (npr. Main), korišćenje Task.Run() u kombinaciji sa Wait() ili pravljenje Main asinhronim, ako verzija C# to podržava (async Task Main).

Primer sigurnog poziva asinhronog koda iz sinhronog metoda koristeći Task.Run za premeštanje izvršenja u pool niti:

// Siguran poziv asinhrone metode iz sinhronog konteksta
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Siguran poziv asinhrone metode sa rezultatom
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;