Sobes.tech
Middle+

Vai ir iespējams sinhroni izsaukt asinhrono kodu?

sobes.tech AI

Atbilde no AI

jā, tas ir iespējams, bet tas var izraisīt problēmas, īpaši deadlockus.

Veidi, kā sinhronizēt asinhrono kodu:

  1. Izmantojot Result īpašību vai Wait() metodi Task objektā:

    // Sinhrons asinhronas metodes izsaukums
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Saņemt asinhronas metodes rezultātu sinhroni
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Izmantojot GetAwaiter().GetResult():

    // Sinhrons asinhronas metodes izsaukums ar rezultāta saņemšanu
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Šāda pieeja ir ar trūkumiem:

  • Deadlock: Visbiežāk sastopamā problēma, īpaši UI pavedienos vai ASP.NET kontekstos, kur Wait() un Result bloķē pašreizējo pavedienu, gaidot uzdevuma pabeigšanu. Ja asinhrona metode mēģina notvert bloķēto sinhronizācijas kontekstu turpinājumam pēc await, rodas deadlock.
  • Veiktspējas un mērogojamības pasliktināšanās: Pavedienu bloķēšana, nevis asinhronu operāciju izmantošana, patērē vairāk resursu un samazina iespēju apstrādāt daudz vienlaicīgu pieprasījumu (piemēram, tīmekļa lietojumprogrammās).
  • Neviendabīga uzvedība: Asinhronā un sinhronā koda sajaukšana var padarīt programmas izpildes plūsmu sarežģītu saprast un labot.

Pareizais veids ir izmantot await asinhronai turpināšanai vai, ja nepieciešams izpildīt asinhrono kodu programmas ieejas punktā (piemēram, Main), izmantot Task.Run() kopā ar Wait() vai padarīt Main asinhronu, ja C# versija to atbalsta (async Task Main).

Drošs piemērs:

// Drošs asinhronas metodes izsaukums no sinhrona konteksta
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Drošs asinhronas metodes izsaukums ar rezultātu
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;