Sobes.tech
Middle+

Kas on võimalik kutsuda asünkroonset koodi sünkroonselt?

sobes.tech AI

Vastus AI-lt

jah, see on võimalik, kuid see võib põhjustada probleeme, eriti deadlock'e.

Meetodid asünkroonse koodi sünkroonselt kutsumiseks:

  1. Kasutades Result omadust või Wait() meetodit Task objektil:

    // Asünkroonse meetodi sünkroonselt kutsumine
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Asünkroonse meetodi tulemuse saamine sünkroonselt
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Kasutades GetAwaiter().GetResult():

    // Asünkroonse meetodi sünkroonselt kutsumine tulemusega
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Negatiivsed aspektid:

  • Deadlock'id: Kõige levinum probleem, eriti UI- või ASP.NET kontekstides, kus Wait() ja Result blokeerivad jooksva niidi, oodates ülesande lõpetamist. Kui asünkroonne meetod püüab haarata blokeeritud sünkroniseerimiskonteksti jätkamiseks pärast await, tekib deadlock.
  • Jõudluse ja skaleeritavuse halvenemine: Niitide blokeerimine asünkroonsete operatsioonide asemel tarbib rohkem ressursse ja vähendab rakenduse võimet töödelda palju samaaegseid päringuid (näiteks veebirakendustes).
  • Mõistmata käitumine: Asünkroonse ja sünkroonse koodi segamine võib muuta programmi täitmise voogu keerulisemaks mõistmiseks ja silumiseks.

Enamikel juhtudel on õige lähenemine await kasutamine asünkroonse täitmise jätkamiseks või, kui on vaja täita asünkroonset koodi rakenduse sisenemispunktis (näiteks Main), kasutada Task.Run() koos Wait()-ga või muuta Main asünkroonseks, kui C# versioon seda toetab (async Task Main).

Turvaline näide:

// Turvaline asünkroonse meetodi kutsumine sünkronilisest kontekstist
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Turvaline asünkroonse meetodi kutsumine tulemusega
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;